diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-10-15 16:07:24 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-15 16:07:24 -0700 |
commit | 021a2b85fb9264d9cb4a21c039682d1f0fddbd1c (patch) | |
tree | 96f39abb25e77769b337aa3d7858c4722c6ba1b4 /src | |
parent | 66dbc57d32bb2c8c01deefba7a035ebed5a42e2c (diff) | |
download | binaryen-021a2b85fb9264d9cb4a21c039682d1f0fddbd1c.tar.gz binaryen-021a2b85fb9264d9cb4a21c039682d1f0fddbd1c.tar.bz2 binaryen-021a2b85fb9264d9cb4a21c039682d1f0fddbd1c.zip |
Support 4GB Memories (#1702)
This fixes asm2wasm parsing of the max to allow 4GB, and also changes the internal Memory::kMaxValue values to reflect that. We used to use kMaxValue to also represent "no limit", so I split that out into kUnlimitedValue.
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 2 | ||||
-rw-r--r-- | src/tools/asm2wasm.cpp | 8 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 2 | ||||
-rw-r--r-- | src/wasm-js.cpp | 4 | ||||
-rw-r--r-- | src/wasm.h | 10 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 7 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 2 |
8 files changed, 29 insertions, 22 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 44666c1e5..de50eb33d 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -759,7 +759,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { EmscriptenGlueGenerator generator(wasm); auto* func = generator.generateMemoryGrowthFunction(); extraSupportFunctions.push_back(func); - wasm.memory.max = Memory::kMaxSize; + wasm.memory.max = Memory::kUnlimitedSize; } // import memory diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp index 1cf7947ce..cc9464434 100644 --- a/src/tools/asm2wasm.cpp +++ b/src/tools/asm2wasm.cpp @@ -197,11 +197,11 @@ int main(int argc, const char *argv[]) { // 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) { + 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::kMaxSize; + wasm.memory.max = Memory::kUnlimitedSize; } } // Set the table sizes, if requested @@ -211,7 +211,7 @@ int main(int argc, const char *argv[]) { if (max >= 0) { wasm.table.max = max; } else { - wasm.table.max = Table::kMaxSize; + wasm.table.max = Table::kUnlimitedSize; } } diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 062fc29a6..fe31290d6 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -268,7 +268,7 @@ private: void finalizeTable() { wasm.table.initial = wasm.table.segments[0].data.size(); - wasm.table.max = oneIn(2) ? Address(Table::kMaxSize) : wasm.table.initial; + wasm.table.max = oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial; } const Name HANG_LIMIT_GLOBAL = "hangLimit"; diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp index a777295d7..381487cd0 100644 --- a/src/wasm-js.cpp +++ b/src/wasm-js.cpp @@ -78,7 +78,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE load_asm2wasm(char *input) { exit(EXIT_FAILURE); } module->memory.initial = Address(providedMemory / Memory::kPageSize); - module->memory.max = pre.memoryGrowth ? Address(Memory::kMaxSize) : module->memory.initial; + module->memory.max = pre.memoryGrowth ? Address(Memory::kUnlimitedSize) : module->memory.initial; if (wasmJSDebug) std::cerr << "wasming...\n"; asm2wasm = new Asm2WasmBuilder(*module, pre, debug, TrapMode::JS, PassOptions(), true /* runJSFFIPass */, false /* TODO: support optimizing? */, false /* TODO: support asm2wasm-i64? */); @@ -94,7 +94,7 @@ void finalizeModule() { exit(EXIT_FAILURE); } module->memory.initial = Address(providedMemory / Memory::kPageSize); - module->memory.max = module->getExportOrNull(GROW_WASM_MEMORY) ? Address(Memory::kMaxSize) : module->memory.initial; + module->memory.max = module->getExportOrNull(GROW_WASM_MEMORY) ? Address(Memory::kUnlimitedSize) : module->memory.initial; // global mapping is done in js in post.js } diff --git a/src/wasm.h b/src/wasm.h index 57591d811..a0f634d17 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -662,6 +662,8 @@ public: class Table : public Importable { public: static const Address::address_t kPageSize = 1; + static const Index kUnlimitedSize = Index(-1); + // In wasm32, the maximum table size is limited by a 32-bit pointer: 4GB static const Index kMaxSize = Index(-1); struct Segment { @@ -684,13 +686,15 @@ public: Table() : exists(false), initial(0), max(kMaxSize) { name = Name::fromInt(0); } - bool hasMax() { return max != kMaxSize; } + bool hasMax() { return max != kUnlimitedSize; } }; class Memory : public Importable { public: static const Address::address_t kPageSize = 64 * 1024; - static const Address::address_t kMaxSize = ~Address::address_t(0) / kPageSize; + static const Address::address_t kUnlimitedSize = Address::address_t(-1); + // In wasm32, the maximum memory size is limited by a 32-bit pointer: 4GB + static const Address::address_t kMaxSize = (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize; static const Address::address_t kPageMask = ~(kPageSize - 1); struct Segment { @@ -718,7 +722,7 @@ public: Memory() : initial(0), max(kMaxSize), exists(false), shared(false) { name = Name::fromInt(0); } - bool hasMax() { return max != kMaxSize; } + bool hasMax() { return max != kUnlimitedSize; } }; class Global : public Importable { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 1839c9cbd..fddb9c3a0 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -143,7 +143,7 @@ void WasmBinaryWriter::writeMemory() { auto start = startSection(BinaryConsts::Section::Memory); o << U32LEB(1); // Define 1 memory writeResizableLimits(wasm->memory.initial, wasm->memory.max, - wasm->memory.max != Memory::kMaxSize, wasm->memory.shared); + wasm->memory.hasMax(), wasm->memory.shared); finishSection(start); } @@ -205,14 +205,14 @@ void WasmBinaryWriter::writeImports() { writeImportHeader(&wasm->memory); o << U32LEB(int32_t(ExternalKind::Memory)); writeResizableLimits(wasm->memory.initial, wasm->memory.max, - wasm->memory.max != Memory::kMaxSize, wasm->memory.shared); + wasm->memory.hasMax(), wasm->memory.shared); } if (wasm->table.imported()) { if (debug) std::cerr << "write one table" << std::endl; writeImportHeader(&wasm->table); o << U32LEB(int32_t(ExternalKind::Table)); o << S32LEB(BinaryConsts::EncodedType::AnyFunc); - writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize, /*shared=*/false); + writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.hasMax(), /*shared=*/false); } finishSection(start); } @@ -418,7 +418,7 @@ void WasmBinaryWriter::writeFunctionTableDeclaration() { auto start = startSection(BinaryConsts::Section::Table); o << U32LEB(1); // Declare 1 table. o << S32LEB(BinaryConsts::EncodedType::AnyFunc); - writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize, /*shared=*/false); + writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.hasMax(), /*shared=*/false); finishSection(start); } @@ -899,7 +899,7 @@ void WasmBinaryBuilder::readMemory() { throwError("Memory cannot be both imported and defined"); } wasm.memory.exists = true; - getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kMaxSize); + getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kUnlimitedSize); } void WasmBinaryBuilder::readSignatures() { @@ -987,7 +987,7 @@ void WasmBinaryBuilder::readImports() { if (elementType != BinaryConsts::EncodedType::AnyFunc) throwError("Imported table type is not AnyFunc"); wasm.table.exists = true; bool is_shared; - getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kMaxSize); + getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize); if (is_shared) throwError("Tables may not be shared"); break; } @@ -996,7 +996,7 @@ void WasmBinaryBuilder::readImports() { wasm.memory.base = base; wasm.memory.name = Name(std::to_string(i)); wasm.memory.exists = true; - getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kMaxSize); + getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kUnlimitedSize); break; } case ExternalKind::Global: { @@ -1542,7 +1542,7 @@ void WasmBinaryBuilder::readFunctionTableDeclaration() { auto elemType = getS32LEB(); if (elemType != BinaryConsts::EncodedType::AnyFunc) throwError("ElementType must be AnyFunc in MVP"); bool is_shared; - getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kMaxSize); + getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kUnlimitedSize); if (is_shared) throwError("Tables may not be shared"); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 7085666bb..ee37f23f3 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1510,7 +1510,10 @@ void SExpressionWasmBuilder::stringToBinary(const char* input, size_t size, std: Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) { wasm.memory.initial = getCheckedAddress(s[i++], "excessive memory init"); - if (i == s.size()) return i; + if (i == s.size()) { + wasm.memory.max = Memory::kUnlimitedSize; + return i; + } uint64_t max = atoll(s[i++]->c_str()); if (max > Memory::kMaxSize) throw ParseException("total memory must be <= 4GB"); wasm.memory.max = max; @@ -1764,7 +1767,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { if (j < inner.size() - 1) { wasm.table.max = getCheckedAddress(inner[j++], "excessive table max size"); } else { - wasm.table.max = Table::kMaxSize; + wasm.table.max = Table::kUnlimitedSize; } // ends with the table element type } else if (kind == ExternalKind::Memory) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 07c7b6aad..fbd31b920 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -969,7 +969,7 @@ static void validateGlobals(Module& module, ValidationInfo& info) { static void validateMemory(Module& module, ValidationInfo& info) { auto& curr = module.memory; info.shouldBeFalse(curr.initial > curr.max, "memory", "memory max >= initial"); - info.shouldBeTrue(curr.max <= Memory::kMaxSize, "memory", "max memory must be <= 4GB"); + info.shouldBeTrue(!curr.hasMax() || curr.max <= Memory::kMaxSize, "memory", "max memory must be <= 4GB, or unlimited"); info.shouldBeTrue(!curr.shared || curr.hasMax(), "memory", "shared memory must have max size"); if (curr.shared) info.shouldBeTrue(info.features & Feature::Atomics, "memory", "memory is shared, but atomics are disabled"); for (auto& segment : curr.segments) { |