diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 2 | ||||
-rw-r--r-- | src/pass.h | 2 | ||||
-rw-r--r-- | src/passes/Print.cpp | 2 | ||||
-rw-r--r-- | src/tools/asm2wasm.cpp | 5 | ||||
-rw-r--r-- | src/tools/feature-options.h | 81 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 18 | ||||
-rw-r--r-- | src/tools/optimization-options.h | 10 | ||||
-rw-r--r-- | src/tools/wasm-as.cpp | 2 | ||||
-rw-r--r-- | src/tools/wasm-opt.cpp | 19 | ||||
-rw-r--r-- | src/tools/wasm-reduce.cpp | 2 | ||||
-rw-r--r-- | src/tools/wasm-shell.cpp | 10 | ||||
-rw-r--r-- | src/wasm-validator.h | 2 | ||||
-rw-r--r-- | src/wasm.h | 40 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 18 |
14 files changed, 154 insertions, 59 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index ebb8bb694..d098810e2 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1936,7 +1936,7 @@ int BinaryenModuleValidate(BinaryenModuleRef module) { Module* wasm = (Module*)module; // TODO add feature selection support to C API - FeatureSet features = Feature::Atomics; + FeatureSet features = FeatureSet::All; return WasmValidator().validate(*wasm, features) ? 1 : 0; } diff --git a/src/pass.h b/src/pass.h index 8064edc32..0a3d85e02 100644 --- a/src/pass.h +++ b/src/pass.h @@ -63,7 +63,7 @@ struct PassOptions { int shrinkLevel = 0; // 0, 1, 2 correspond to -O0, -Os, -Oz bool ignoreImplicitTraps = false; // optimize assuming things like div by 0, bad load/store, will not trap bool debugInfo = false; // whether to try to preserve debug info through, which are special calls - FeatureSet features = Feature::MVP; // Which wasm features to accept, and be allowed to use + FeatureSet features = FeatureSet::All; // Which wasm features to accept, and be allowed to use void setDefaultOptimizationOptions() { // -Os is our default diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 02fc2a83b..e874321cd 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1184,7 +1184,7 @@ Pass* createPrintStackIRPass() { std::ostream& WasmPrinter::printModule(Module* module, std::ostream& o) { PassRunner passRunner(module); - passRunner.setFeatures(Feature::All); + passRunner.setFeatures(FeatureSet::All); passRunner.setIsNested(true); passRunner.add<Printer>(&o); passRunner.run(); diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp index d5e5827c5..a001c08a6 100644 --- a/src/tools/asm2wasm.cpp +++ b/src/tools/asm2wasm.cpp @@ -115,9 +115,6 @@ int main(int argc, const char *argv[]) { .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("--enable-threads", "-a", "Enable the Atomics wasm feature", - Options::Arguments::Zero, - [&](Options *o, const std::string& argument) { options.passOptions.features |= Feature::Atomics; }) .add_positional("INFILE", Options::Arguments::One, [](Options *o, const std::string& argument) { o->extra["infile"] = argument; @@ -188,7 +185,7 @@ int main(int argc, const char *argv[]) { if (memInit != options.extra.end()) { if (options.runningDefaultOptimizationPasses()) { PassRunner runner(&wasm); - runner.setFeatures(options.features); + runner.setFeatures(options.getFeatures()); runner.add("memory-packing"); runner.run(); } diff --git a/src/tools/feature-options.h b/src/tools/feature-options.h new file mode 100644 index 000000000..3b35656fc --- /dev/null +++ b/src/tools/feature-options.h @@ -0,0 +1,81 @@ +/* + * Copyright 2018 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. + */ + +#include "support/command-line.h" +#include "pass.h" + +// +// Shared optimization options for commandline tools +// + +namespace wasm { + +struct FeatureOptions : public Options { + PassOptions passOptions; + + FeatureOptions(const std::string& command, const std::string& description) + : Options(command, description) { + (*this) + .add("--mvp-features", "-mvp", "Disable all non-MVP features (default)", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features = FeatureSet::MVP; + }) + .add("--all-features", "-all", "Enable all features", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features = FeatureSet::All; + }) + .add("--enable-threads", "", "Enable atomic operations", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features.setAtomics(); + }) + .add("--disable-threads", "", "Disable atomic operations", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features.setAtomics(false); + }) + .add("--enable-mutable-globals", "", "Enable mutable globals", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features.setMutableGlobals(); + }) + .add("--disable-mutable-globals", "", "Disable mutable globals", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features.setMutableGlobals(false); + }) + .add("--enable-nontrapping-float-to-int", "", + "Enable nontrapping float-to-int operations", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features.setTruncSat(); + }) + .add("--disable-nontrapping-float-to-int", "", + "Disable nontrapping float-to-int operations", + Options::Arguments::Zero, + [this](Options *o, const std::string& arguments) { + passOptions.features.setTruncSat(false); + }); + } + + FeatureSet getFeatures() const { + return passOptions.features; + } +}; + +} // namespace wasm diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 7954229c7..8f7123a78 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -123,8 +123,8 @@ public: std::cout << "shrink level: " << options.passOptions.shrinkLevel << '\n'; } - void build(bool initEmitAtomics = true) { - emitAtomics = initEmitAtomics; + void build(FeatureSet features_) { + features = features_; setupMemory(); setupTable(); setupGlobals(); @@ -179,8 +179,8 @@ private: // cross-VM comparisons harder) static const bool DE_NAN = true; - // Whether to emit atomics - bool emitAtomics = true; + // Features allowed to be emitted + FeatureSet features = FeatureSet::All; // Whether to emit atomic waits (which in single-threaded mode, may hang...) static const bool ATOMIC_WAITS = false; @@ -1118,7 +1118,7 @@ private: Expression* makeLoad(Type type) { auto* ret = makeNonAtomicLoad(type); if (type != i32 && type != i64) return ret; - if (!emitAtomics || oneIn(2)) return ret; + if (!features.hasAtomics() || oneIn(2)) return ret; // make it atomic wasm.memory.shared = true; ret->isAtomic = true; @@ -1181,7 +1181,7 @@ private: Store* makeStore(Type type) { auto* ret = makeNonAtomicStore(type); if (ret->value->type != i32 && ret->value->type != i64) return ret; - if (!emitAtomics || oneIn(2)) return ret; + if (!features.hasAtomics() || oneIn(2)) return ret; // make it atomic wasm.memory.shared = true; ret->isAtomic = true; @@ -1314,7 +1314,7 @@ private: case i32: { switch (upTo(4)) { case 0: { - if (emitAtomics) { + if (features.hasAtomics()) { return makeUnary({ pick(EqZInt32, ClzInt32, CtzInt32, PopcntInt32, ExtendS8Int32, ExtendS16Int32), make(i32) }); } else { return makeUnary({ pick(EqZInt32, ClzInt32, CtzInt32, PopcntInt32), make(i32) }); @@ -1330,7 +1330,7 @@ private: case i64: { switch (upTo(4)) { case 0: { - if (emitAtomics) { + if (features.hasAtomics()) { return makeUnary({ pick(ClzInt64, CtzInt64, PopcntInt64, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64), make(i64) }); } else { return makeUnary({ pick(ClzInt64, CtzInt64, PopcntInt64), make(i64) }); @@ -1465,7 +1465,7 @@ private: } Expression* makeAtomic(Type type) { - if (!emitAtomics || (type != i32 && type != i64)) return makeTrivial(type); + if (!features.hasAtomics() || (type != i32 && type != i64)) return makeTrivial(type); wasm.memory.shared = true; if (type == i32 && oneIn(2)) { if (ATOMIC_WAITS && oneIn(2)) { diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index abe3bcd6d..7849be375 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "support/command-line.h" +#include "feature-options.h" // // Shared optimization options for commandline tools @@ -22,14 +22,12 @@ namespace wasm { -struct OptimizationOptions : public Options { +struct OptimizationOptions : public FeatureOptions { static constexpr const char* DEFAULT_OPT_PASSES = "O"; std::vector<std::string> passes; - PassOptions passOptions; - FeatureSet features = Feature::Atomics; - OptimizationOptions(const std::string& command, const std::string& description) : Options(command, description) { + OptimizationOptions(const std::string& command, const std::string& description) : FeatureOptions(command, description) { (*this).add("", "-O", "execute default optimization passes", Options::Arguments::Zero, [this](Options*, const std::string&) { @@ -132,7 +130,7 @@ struct OptimizationOptions : public Options { void runPasses(Module& wasm) { PassRunner passRunner(&wasm, passOptions); if (debug) passRunner.setDebug(true); - passRunner.setFeatures(features); + passRunner.setFeatures(passOptions.features); for (auto& pass : passes) { if (pass == DEFAULT_OPT_PASSES) { passRunner.addDefaultOptimizationPasses(); diff --git a/src/tools/wasm-as.cpp b/src/tools/wasm-as.cpp index 46885dec0..c504c2a81 100644 --- a/src/tools/wasm-as.cpp +++ b/src/tools/wasm-as.cpp @@ -93,7 +93,7 @@ int main(int argc, const char *argv[]) { if (options.extra["validate"] != "none") { if (options.debug) std::cerr << "Validating..." << std::endl; - if (!wasm::WasmValidator().validate(wasm, Feature::All, + if (!wasm::WasmValidator().validate(wasm, FeatureSet::All, WasmValidator::Globally | (options.extra["validate"] == "web" ? WasmValidator::Web : 0))) { WasmPrinter::printModule(&wasm); Fatal() << "Error: input module is not valid.\n"; diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 421bcca59..3e04fc644 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -69,7 +69,6 @@ int main(int argc, const char* argv[]) { bool fuzzBinary = false; std::string extraFuzzCommand; bool translateToFuzz = false; - bool fuzzAtomics = true; bool fuzzPasses = false; std::string emitJSWrapper; std::string emitSpecWrapper; @@ -106,9 +105,6 @@ int main(int argc, const char* argv[]) { .add("--translate-to-fuzz", "-ttf", "Translate the input into a valid wasm module *somehow*, useful for fuzzing", Options::Arguments::Zero, [&](Options *o, const std::string& arguments) { translateToFuzz = true; }) - .add("--no-fuzz-atomics", "-nfa", "Disable generation of atomic opcodes with translate-to-fuzz (on by default)", - Options::Arguments::Zero, - [&](Options *o, const std::string& arguments) { fuzzAtomics = false; }) .add("--fuzz-passes", "-fp", "Pick a random set of passes to run, useful for fuzzing. this depends on translate-to-fuzz (it picks the passes from the input)", Options::Arguments::Zero, [&](Options *o, const std::string& arguments) { fuzzPasses = true; }) @@ -134,11 +130,6 @@ int main(int argc, const char* argv[]) { options.parse(argc, argv); Module wasm; - // It should be safe to just always enable atomics in wasm-opt, because we - // don't expect any passes to accidentally generate atomic ops - FeatureSet features = Feature::Atomics; - // Same for MutableGlobals - features |= Feature::MutableGlobals; if (options.debug) std::cerr << "reading...\n"; @@ -160,7 +151,7 @@ int main(int argc, const char* argv[]) { } if (options.passOptions.validate) { - if (!WasmValidator().validate(wasm, features)) { + if (!WasmValidator().validate(wasm, options.getFeatures())) { WasmPrinter::printModule(&wasm); Fatal() << "error in validating input"; } @@ -171,9 +162,9 @@ int main(int argc, const char* argv[]) { if (fuzzPasses) { reader.pickPasses(options); } - reader.build(fuzzAtomics); + reader.build(options.getFeatures()); if (options.passOptions.validate) { - if (!WasmValidator().validate(wasm, features)) { + if (!WasmValidator().validate(wasm, options.getFeatures())) { WasmPrinter::printModule(&wasm); std::cerr << "translate-to-fuzz must always generate a valid module"; abort(); @@ -226,7 +217,7 @@ int main(int argc, const char* argv[]) { WasmBinaryBuilder parser(other, input, false); parser.read(); if (options.passOptions.validate) { - bool valid = WasmValidator().validate(other, features); + bool valid = WasmValidator().validate(other, options.getFeatures()); if (!valid) { WasmPrinter::printModule(&other); } @@ -240,7 +231,7 @@ int main(int argc, const char* argv[]) { auto runPasses = [&]() { options.runPasses(*curr); if (options.passOptions.validate) { - bool valid = WasmValidator().validate(*curr, features); + bool valid = WasmValidator().validate(*curr, options.getFeatures()); if (!valid) { WasmPrinter::printModule(&*curr); } diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 5c1f98d88..8c5df7a1b 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -797,7 +797,7 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor< FunctionReferenceRemover referenceRemover(names); referenceRemover.walkModule(module.get()); - if (WasmValidator().validate(*module, Feature::All, WasmValidator::Globally | WasmValidator::Quiet) && + if (WasmValidator().validate(*module, FeatureSet::All, WasmValidator::Globally | WasmValidator::Quiet) && writeAndTestReduction()) { std::cerr << "| removed " << names.size() << " functions\n"; return true; diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 9ad1fa799..d8cd11f41 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -23,9 +23,9 @@ #include <memory> #include "execution-results.h" +#include "feature-options.h" #include "pass.h" #include "shell-interface.h" -#include "support/command-line.h" #include "support/file.h" #include "wasm-interpreter.h" #include "wasm-printing.h" @@ -233,14 +233,14 @@ int main(int argc, const char* argv[]) { Name entry; std::set<size_t> skipped; - Options options("wasm-shell", "Execute .wast files"); + FeatureOptions options("wasm-shell", "Execute .wast files"); options .add( - "--entry", "-e", "call the entry point after parsing the module", + "--entry", "-e", "Call the entry point after parsing the module", Options::Arguments::One, [&entry](Options*, const std::string& argument) { entry = argument; }) .add( - "--skip", "-s", "skip input on certain lines (comma-separated-list)", + "--skip", "-s", "Skip input on certain lines (comma-separated-list)", Options::Arguments::One, [&skipped](Options*, const std::string& argument) { size_t i = 0; @@ -292,7 +292,7 @@ int main(int argc, const char* argv[]) { builders[moduleName].swap(builder); modules[moduleName].swap(module); i++; - bool valid = WasmValidator().validate(*modules[moduleName]); + bool valid = WasmValidator().validate(*modules[moduleName], options.getFeatures()); if (!valid) { WasmPrinter::printModule(modules[moduleName].get()); } diff --git a/src/wasm-validator.h b/src/wasm-validator.h index 81d65a6bd..3c0b6018b 100644 --- a/src/wasm-validator.h +++ b/src/wasm-validator.h @@ -57,7 +57,7 @@ struct WasmValidator { }; typedef uint32_t Flags; - bool validate(Module& module, FeatureSet features = MVP, Flags flags = Globally); + bool validate(Module& module, FeatureSet features = FeatureSet::MVP, Flags flags = Globally); }; } // namespace wasm diff --git a/src/wasm.h b/src/wasm.h index 424f89d0b..1d5677134 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -37,13 +37,41 @@ namespace wasm { -enum Feature : uint32_t { - MVP = 0, - Atomics = 1 << 0, - MutableGlobals = 1 << 1, - All = 0xffffffff, +struct FeatureSet { + enum Feature : uint32_t { + MVP = 0, + Atomics = 1 << 0, + MutableGlobals = 1 << 1, + TruncSat = 1 << 2, + All = Atomics | MutableGlobals | TruncSat + }; + + FeatureSet() : features(MVP) {} + FeatureSet(uint32_t features) : features(features) {} + + bool isMVP() const { return features == MVP; } + bool hasAtomics() const { return features & Atomics; } + bool hasMutableGlobals() const { return features & MutableGlobals; } + bool hasTruncSat() const { return features & TruncSat; } + bool hasAll() const { return features & (Atomics | MutableGlobals | TruncSat); } + + void makeMVP() { features = MVP; } + void setAtomics(bool v = true) { + features = v ? (features | Atomics) : (features & ~Atomics); + } + void setMutableGlobals(bool v = true) { + features = v ? (features | MutableGlobals) : (features & ~MutableGlobals); + } + void setTruncSat(bool v = true) { + features = v ? (features | TruncSat) : (features & ~TruncSat); + } + void setAll(bool v = true) { + features = v ? All : MVP; + } + + private: + uint32_t features; }; -typedef uint32_t FeatureSet; // An index in a wasm module typedef uint32_t Index; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index b88a94e6d..fa239688f 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -497,7 +497,7 @@ void FunctionValidator::visitSetGlobal(SetGlobal* curr) { } void FunctionValidator::visitLoad(Load* curr) { - if (curr->isAtomic) shouldBeTrue(info.features & Feature::Atomics, curr, "Atomic operation (atomics are disabled)"); + if (curr->isAtomic) shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->type, curr); validateAlignment(curr->align, curr->type, curr->bytes, curr->isAtomic, curr); @@ -509,7 +509,7 @@ void FunctionValidator::visitLoad(Load* curr) { } void FunctionValidator::visitStore(Store* curr) { - if (curr->isAtomic) shouldBeTrue(info.features & Feature::Atomics, curr, "Atomic operation (atomics are disabled)"); + if (curr->isAtomic) shouldBeTrue(info.features.hasAtomics(), curr, "Atomic operation (atomics are disabled)"); shouldBeFalse(curr->isAtomic && !getModule()->memory.shared, curr, "Atomic operation with non-shared memory"); validateMemBytes(curr->bytes, curr->valueType, curr); validateAlignment(curr->align, curr->type, curr->bytes, curr->isAtomic, curr); @@ -522,7 +522,7 @@ void FunctionValidator::visitStore(Store* curr) { } void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) { - shouldBeTrue(info.features & Feature::Atomics, curr, "Atomic operation (atomics are disabled)"); + 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); shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "AtomicRMW pointer type must be i32"); @@ -531,7 +531,7 @@ void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) { } void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) { - shouldBeTrue(info.features & Feature::Atomics, curr, "Atomic operation (atomics are disabled)"); + 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); shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "cmpxchg pointer type must be i32"); @@ -544,7 +544,7 @@ void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) { } void FunctionValidator::visitAtomicWait(AtomicWait* curr) { - shouldBeTrue(info.features & Feature::Atomics, curr, "Atomic operation (atomics are disabled)"); + 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"); shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "AtomicWait pointer type must be i32"); @@ -554,7 +554,7 @@ void FunctionValidator::visitAtomicWait(AtomicWait* curr) { } void FunctionValidator::visitAtomicWake(AtomicWake* curr) { - shouldBeTrue(info.features & Feature::Atomics, curr, "Atomic operation (atomics are disabled)"); + 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, "AtomicWake must have type i32"); shouldBeEqualOrFirstIsUnreachable(curr->ptr->type, i32, curr, "AtomicWake pointer type must be i32"); @@ -923,7 +923,7 @@ static void validateImports(Module& module, ValidationInfo& info) { } } }); - if (!(info.features & Feature::MutableGlobals)) { + if (!info.features.hasMutableGlobals()) { ModuleUtils::iterImportedGlobals(module, [&](Global* curr) { info.shouldBeFalse(curr->mutable_, curr->name, "Imported global cannot be mutable"); }); @@ -940,7 +940,7 @@ static void validateExports(Module& module, ValidationInfo& info) { info.shouldBeUnequal(param, i64, f->name, "Exported function must not have i64 parameters"); } } - } else if (curr->kind == ExternalKind::Global && !(info.features & Feature::MutableGlobals)) { + } else if (curr->kind == ExternalKind::Global && !info.features.hasMutableGlobals()) { if (Global* g = module.getGlobalOrNull(curr->value)) { info.shouldBeFalse(g->mutable_, g->name, "Exported global cannot be mutable"); } @@ -981,7 +981,7 @@ static void validateMemory(Module& module, ValidationInfo& info) { info.shouldBeFalse(curr.initial > curr.max, "memory", "memory max >= initial"); 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"); + if (curr.shared) info.shouldBeTrue(info.features.hasAtomics(), "memory", "memory is shared, but atomics are disabled"); for (auto& segment : curr.segments) { if (!info.shouldBeEqual(segment.offset->type, i32, segment.offset, "segment offset should be i32")) continue; info.shouldBeTrue(checkOffset(segment.offset, segment.data.size(), curr.initial * Memory::kPageSize), segment.offset, "segment offset should be reasonable"); |