diff options
author | Alon Zakai <alonzakai@gmail.com> | 2019-04-03 17:49:47 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-03 17:49:47 -0700 |
commit | 773759f7842611bbe3e30f7b9d4cd24350291976 (patch) | |
tree | a2ac1d3b7e1850b3827b087f671c6182b39429b2 /src | |
parent | 02198da745469104cb6ced60b37efa8d8a7f4464 (diff) | |
download | binaryen-773759f7842611bbe3e30f7b9d4cd24350291976.tar.gz binaryen-773759f7842611bbe3e30f7b9d4cd24350291976.tar.bz2 binaryen-773759f7842611bbe3e30f7b9d4cd24350291976.zip |
Update test/spec/memory.wast to latest upstream (#1801)
Minus multi-memory which we don't support yet.
Improve validator.
Fix some minor validation issues in our tests.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/memory-utils.h | 8 | ||||
-rw-r--r-- | src/passes/I64ToI32Lowering.cpp | 9 | ||||
-rw-r--r-- | src/passes/RemoveNonJSOps.cpp | 4 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 5 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 11 |
5 files changed, 34 insertions, 3 deletions
diff --git a/src/ir/memory-utils.h b/src/ir/memory-utils.h index 5980a3218..c8f39a2ec 100644 --- a/src/ir/memory-utils.h +++ b/src/ir/memory-utils.h @@ -48,6 +48,14 @@ namespace MemoryUtils { memory.segments[0].data.swap(data); return true; } + + // Ensures that the memory exists (of minimal size). + inline void ensureExists(Memory& memory) { + if (!memory.exists) { + memory.exists = true; + memory.initial = memory.max = 1; + } + } }; } // namespace wasm diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index 4575dd2f8..ae69ec19d 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -27,6 +27,7 @@ #include "emscripten-optimizer/istring.h" #include "support/name.h" #include "wasm-builder.h" +#include "ir/memory-utils.h" #include "ir/module-utils.h" #include "ir/names.h" #include "asmjs/shared-constants.h" @@ -608,6 +609,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { ); setOutParam(result, std::move(highBits)); replaceCurrent(result); + ensureMinimalMemory(); } void lowerReinterpretInt64(Unary* curr) { @@ -620,6 +622,13 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { builder->makeLoad(8, true, 0, 8, builder->makeConst(Literal(int32_t(0))), f64) ); replaceCurrent(result); + ensureMinimalMemory(); + } + + // Ensure memory exists with a minimal size, enough for round-tripping operations on + // address 0, which we need for reinterpret operations. + void ensureMinimalMemory() { + MemoryUtils::ensureExists(getModule()->memory); } void lowerTruncFloatToInt(Unary *curr) { diff --git a/src/passes/RemoveNonJSOps.cpp b/src/passes/RemoveNonJSOps.cpp index cc9a40a1f..342f59eba 100644 --- a/src/passes/RemoveNonJSOps.cpp +++ b/src/passes/RemoveNonJSOps.cpp @@ -33,6 +33,7 @@ #include "asmjs/shared-constants.h" #include "wasm-builder.h" #include "wasm-s-parser.h" +#include "ir/memory-utils.h" #include "ir/module-utils.h" #include "ir/find_all.h" #include "passes/intrinsics-module.h" @@ -97,6 +98,9 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> { } neededFunctions.clear(); } + + // Intrinsics may use memory, so ensure the module has one. + MemoryUtils::ensureExists(module->memory); } void addNeededFunctions(Module &m, Name name, std::set<Name> &needed) { diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 6aa0764f1..b17be8afe 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -29,6 +29,7 @@ high chance for set at start of loop #include <ir/find_all.h> #include <ir/literal-utils.h> #include <ir/manipulation.h> +#include "ir/memory-utils.h" #include <ir/utils.h> namespace wasm { @@ -254,9 +255,7 @@ private: } void setupMemory() { - wasm.memory.exists = true; - // use one page - wasm.memory.initial = wasm.memory.max = 1; + MemoryUtils::ensureExists(wasm.memory); // init some data wasm.memory.segments.emplace_back(builder.makeConst(Literal(int32_t(0)))); auto num = upTo(USABLE_MEMORY * 2); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 6d4490982..79c1d4f9b 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -512,6 +512,7 @@ void FunctionValidator::visitSetGlobal(SetGlobal* curr) { } void FunctionValidator::visitLoad(Load* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); if (curr->isAtomic) { shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeTrue(curr->type == i32 || curr->type == i64 || curr->type == unreachable, curr, "Atomic load should be i32 or i64"); @@ -528,6 +529,7 @@ void FunctionValidator::visitLoad(Load* curr) { } void FunctionValidator::visitStore(Store* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); if (curr->isAtomic) { shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeTrue(curr->valueType == i32 || curr->valueType == i64 || curr->valueType == unreachable, curr, "Atomic store should be i32 or i64"); @@ -545,6 +547,7 @@ void FunctionValidator::visitStore(Store* curr) { } void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->type, curr); @@ -554,6 +557,7 @@ void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) { } void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->type, curr); @@ -567,6 +571,7 @@ void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) { } void FunctionValidator::visitAtomicWait(AtomicWait* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); shouldBeEqualOrFirstIsUnreachable(curr->type, i32, curr, "AtomicWait must have type i32"); @@ -577,6 +582,7 @@ void FunctionValidator::visitAtomicWait(AtomicWait* curr) { } void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(!getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); shouldBeEqualOrFirstIsUnreachable(curr->type, i32, curr, "AtomicNotify must have type i32"); @@ -647,6 +653,7 @@ void FunctionValidator::visitSIMDShift(SIMDShift* curr) { } void FunctionValidator::visitMemoryInit(MemoryInit* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.init must have type none"); shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.init dest must be an i32"); @@ -656,12 +663,14 @@ void FunctionValidator::visitMemoryInit(MemoryInit* curr) { } void FunctionValidator::visitDataDrop(DataDrop* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "data.drop must have type none"); shouldBeTrue(curr->segment < getModule()->memory.segments.size(), curr, "data.drop segment index out of bounds"); } void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.copy must have type none"); shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.copy dest must be an i32"); @@ -670,6 +679,7 @@ void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) { } void FunctionValidator::visitMemoryFill(MemoryFill* curr) { + shouldBeTrue(getModule()->memory.exists, curr, "Memory operations require a memory"); shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.fill must have type none"); shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.fill dest must be an i32"); @@ -1289,6 +1299,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.initial <= Memory::kMaxSize, "memory", "initial 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.hasAtomics(), "memory", "memory is shared, but atomics are disabled"); |