summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-10-15 16:07:24 -0700
committerGitHub <noreply@github.com>2018-10-15 16:07:24 -0700
commit021a2b85fb9264d9cb4a21c039682d1f0fddbd1c (patch)
tree96f39abb25e77769b337aa3d7858c4722c6ba1b4 /src
parent66dbc57d32bb2c8c01deefba7a035ebed5a42e2c (diff)
downloadbinaryen-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.h2
-rw-r--r--src/tools/asm2wasm.cpp8
-rw-r--r--src/tools/fuzzing.h2
-rw-r--r--src/wasm-js.cpp4
-rw-r--r--src/wasm.h10
-rw-r--r--src/wasm/wasm-binary.cpp16
-rw-r--r--src/wasm/wasm-s-parser.cpp7
-rw-r--r--src/wasm/wasm-validator.cpp2
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) {