Bug 1651799 - Remove bulk-memory configuration options. r=bbouvier

Bulk memory is now enabled for all compilers and platforms, so let's remove the
configuration machinery for it.

Differential Revision: https://phabricator.services.mozilla.com/D83423
This commit is contained in:
Ryan Hunt 2020-07-27 21:13:35 +00:00
Родитель d03c6c2687
Коммит 77b6f1962f
16 изменённых файлов: 55 добавлений и 289 удалений

Просмотреть файл

@ -508,20 +508,6 @@ set_config('JS_HAS_TYPED_OBJECTS', depends_if('--enable-typed-objects')(lambda x
set_define('JS_HAS_TYPED_OBJECTS', depends_if('--enable-typed-objects')(lambda x: True))
# Support for WebAssembly bulk memory operations.
# =====================================================
js_option('--disable-wasm-bulk-memory',
help='Disable WebAssembly bulk memory operators')
@depends('--disable-wasm-bulk-memory')
def enable_wasm_bulk_memory(value):
if value:
return True
set_config('ENABLE_WASM_BULKMEM_OPS', enable_wasm_bulk_memory)
set_define('ENABLE_WASM_BULKMEM_OPS', enable_wasm_bulk_memory)
# Support for WebAssembly reference types.
# =====================================================

Просмотреть файл

@ -792,18 +792,6 @@ static bool WasmThreadsSupported(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
static bool WasmBulkMemSupported(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef ENABLE_WASM_BULKMEM_OPS
bool isSupported = true;
#else
bool isSupported =
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
#endif
args.rval().setBoolean(isSupported);
return true;
}
static bool WasmReftypesEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::ReftypesAvailable(cx));
@ -6451,11 +6439,6 @@ gc::ZealModeHelpText),
JS_FN_HELP("wasmThreadsSupported", WasmThreadsSupported, 0, 0,
"wasmThreadsSupported()",
" Returns a boolean indicating whether the WebAssembly threads proposal is\n"
" supported on the current device."),
JS_FN_HELP("wasmBulkMemSupported", WasmBulkMemSupported, 0, 0,
"wasmBulkMemSupported()",
" Returns a boolean indicating whether the WebAssembly bulk memory proposal is\n"
" supported on the current device."),
JS_FN_HELP("wasmSimdSupported", WasmSimdSupported, 0, 0,

Просмотреть файл

@ -54,8 +54,6 @@ parent = "spec"
excluded_tests = []
# Skip in WPT where we can't guard on features being enabled
skip_wpt = true
# Skip in jit-test when it's not enabled
directive = "; skip-if: !wasmBulkMemSupported()"
[[repos]]
name = "reference-types"
@ -65,4 +63,4 @@ excluded_tests = []
# Skip in WPT where we can't guard on features being enabled
skip_wpt = true
# Skip in jit-test when it's not enabled
directive = "; skip-if: !wasmBulkMemSupported() || !wasmReftypesEnabled()"
directive = "; skip-if: !wasmReftypesEnabled()"

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmBulkMemSupported() || !wasmReftypesEnabled()
// |jit-test| skip-if: !wasmReftypesEnabled()
// Declared segments parse and validate
wasmFullPass(`

Просмотреть файл

@ -16,11 +16,7 @@ const tab3Elem = new Table({initial:3, element:"funcref"});
const tab4Elem = new Table({initial:4, element:"funcref"});
function assertSegmentFitError(f) {
if (wasmBulkMemSupported()) {
assertErrorMessage(f, RuntimeError, /out of bounds/);
} else {
assertErrorMessage(f, LinkError, /segment does not fit/);
}
assertErrorMessage(f, RuntimeError, /out of bounds/);
}
const m1 = new Module(wasmTextToBinary('(module (import "foo" "bar" (func)) (import "baz" "quux" (func)))'));
@ -500,15 +496,11 @@ var mem8 = new Uint8Array(mem.buffer);
var tbl = new Table({initial:2, element:"funcref"});
assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:1, tblOff:2}}));
if (wasmBulkMemSupported()) {
// The first active element segment is applied, but the second active
// element segment is completely OOB.
assertEq(typeof tbl.get(0), "function");
assertEq(tbl.get(1), null);
} else if (!wasmCompileMode().match("cranelift")) {
assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null);
}
// The first active element segment is applied, but the second active
// element segment is completely OOB.
assertEq(typeof tbl.get(0), "function");
assertEq(tbl.get(1), null);
assertEq(mem8[0], 0);
assertEq(mem8[1], 0);
@ -516,17 +508,11 @@ tbl.set(0, null);
tbl.set(1, null);
assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:npages*64*1024, tblOff:1}}));
if (wasmBulkMemSupported()) {
// The first and second active element segments are applied fully. The
// first active data segment applies, but the second one is completely OOB.
assertEq(typeof tbl.get(0), "function");
assertEq(typeof tbl.get(1), "function");
assertEq(mem8[0], 1);
} else if (!wasmCompileMode().match("cranelift")) {
assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null);
assertEq(mem8[0], 0);
}
// The first and second active element segments are applied fully. The
// first active data segment applies, but the second one is completely OOB.
assertEq(typeof tbl.get(0), "function");
assertEq(typeof tbl.get(1), "function");
assertEq(mem8[0], 1);
tbl.set(0, null);
tbl.set(1, null);
@ -543,44 +529,40 @@ assertEq(tbl.get(1), i.exports.g);
// Element segment doesn't apply and prevents subsequent elem segment and
// data segment from being applied.
if (wasmBulkMemSupported()) {
let m = new Module(wasmTextToBinary(
`(module
(import "" "mem" (memory 1))
(import "" "tbl" (table 3 funcref))
(elem (i32.const 1) $f $g $h) ;; fails after $f and $g
(elem (i32.const 0) $f) ;; is not applied
(data (i32.const 0) "\\01") ;; is not applied
(func $f)
(func $g)
(func $h))`));
let mem = new Memory({initial:1});
let tbl = new Table({initial:3, element:"funcref"});
assertSegmentFitError(() => new Instance(m, {"":{mem, tbl}}));
assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null);
assertEq(tbl.get(2), null);
let v = new Uint8Array(mem.buffer);
assertEq(v[0], 0);
}
var m = new Module(wasmTextToBinary(
`(module
(import "" "mem" (memory 1))
(import "" "tbl" (table 3 funcref))
(elem (i32.const 1) $f $g $h) ;; fails after $f and $g
(elem (i32.const 0) $f) ;; is not applied
(data (i32.const 0) "\\01") ;; is not applied
(func $f)
(func $g)
(func $h))`));
var mem = new Memory({initial:1});
var tbl = new Table({initial:3, element:"funcref"});
assertSegmentFitError(() => new Instance(m, {"":{mem, tbl}}));
assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null);
assertEq(tbl.get(2), null);
var v = new Uint8Array(mem.buffer);
assertEq(v[0], 0);
// Data segment doesn't apply and prevents subsequent data segment from
// being applied.
if (wasmBulkMemSupported()) {
let m = new Module(wasmTextToBinary(
`(module
(import "" "mem" (memory 1))
(data (i32.const 65534) "\\01\\02\\03") ;; fails after 1 and 2
(data (i32.const 0) "\\04") ;; is not applied
)`));
let mem = new Memory({initial:1});
assertSegmentFitError(() => new Instance(m, {"":{mem}}));
let v = new Uint8Array(mem.buffer);
assertEq(v[65534], 0);
assertEq(v[65535], 0);
assertEq(v[0], 0);
}
var m = new Module(wasmTextToBinary(
`(module
(import "" "mem" (memory 1))
(data (i32.const 65534) "\\01\\02\\03") ;; fails after 1 and 2
(data (i32.const 0) "\\04") ;; is not applied
)`));
var mem = new Memory({initial:1});
assertSegmentFitError(() => new Instance(m, {"":{mem}}));
var v = new Uint8Array(mem.buffer);
assertEq(v[65534], 0);
assertEq(v[65535], 0);
assertEq(v[0], 0);
// Elem segments on imported tables

Просмотреть файл

@ -1,5 +1,3 @@
// |jit-test| skip-if: !wasmBulkMemSupported()
// Perform a test which,
//
// * if errKind is defined, is expected to fail with an exception

Просмотреть файл

@ -1,5 +1,3 @@
// |jit-test| skip-if: !wasmBulkMemSupported()
load(libdir + "wasm-binary.js");
const v2vSig = {args:[], ret:VoidCode};

Просмотреть файл

@ -1,5 +1,3 @@
// |jit-test| skip-if: !wasmBulkMemSupported()
let conf = getBuildConfiguration();
if (conf.debug &&
(conf["arm-simulator"] || conf["arm64-simulator"] ||

Просмотреть файл

@ -1,5 +1,3 @@
// |jit-test| skip-if: !wasmBulkMemSupported()
// Sundry test cases for the "partial write" bounds checking semantics.
// table.init: out of bounds of the table or the element segment, and should

Просмотреть файл

@ -1 +1 @@
|jit-test| test-also=--wasm-compiler=ion; test-also=--wasm-compiler=baseline; test-also=--test-wasm-await-tier2; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemoryIsSupported(); include:wasm-testharness.js; local-include:harness/sync_index.js; skip-if: !wasmBulkMemSupported()
|jit-test| test-also=--wasm-compiler=ion; test-also=--wasm-compiler=baseline; test-also=--test-wasm-await-tier2; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemoryIsSupported(); include:wasm-testharness.js; local-include:harness/sync_index.js

Просмотреть файл

@ -1 +1 @@
|jit-test| test-also=--wasm-compiler=ion; test-also=--wasm-compiler=baseline; test-also=--test-wasm-await-tier2; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemoryIsSupported(); include:wasm-testharness.js; local-include:harness/sync_index.js; skip-if: !wasmBulkMemSupported() || !wasmReftypesEnabled()
|jit-test| test-also=--wasm-compiler=ion; test-also=--wasm-compiler=baseline; test-also=--test-wasm-await-tier2; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemoryIsSupported(); include:wasm-testharness.js; local-include:harness/sync_index.js; skip-if: !wasmReftypesEnabled()

Просмотреть файл

@ -8,11 +8,7 @@ const RuntimeError = WebAssembly.RuntimeError;
const badFuncRefError = /can only pass WebAssembly exported functions to funcref/;
function assertSegmentFitError(f) {
if (wasmBulkMemSupported()) {
assertErrorMessage(f, RuntimeError, /out of bounds/);
} else {
assertErrorMessage(f, LinkError, /segment does not fit/);
}
assertErrorMessage(f, RuntimeError, /out of bounds/);
}
var callee = i => `(func $f${i} (result i32) (i32.const ${i}))`;

Просмотреть файл

@ -8073,7 +8073,6 @@ class BaseCompiler final : public BaseCompilerInterface {
MOZ_MUST_USE bool emitFence();
MOZ_MUST_USE bool emitAtomicXchg(ValType type, Scalar::Type viewType);
void emitAtomicXchg64(MemoryAccessDesc* access, WantResult wantResult);
MOZ_MUST_USE bool bulkmemOpsEnabled();
MOZ_MUST_USE bool emitMemCopy();
MOZ_MUST_USE bool emitMemCopyCall(uint32_t lineOrBytecode);
MOZ_MUST_USE bool emitMemCopyInline();
@ -11741,21 +11740,7 @@ bool BaseCompiler::emitFence() {
return true;
}
// Bulk memory must be available if shared memory is enabled.
bool BaseCompiler::bulkmemOpsEnabled() {
#ifndef ENABLE_WASM_BULKMEM_OPS
if (env_.sharedMemoryEnabled == Shareable::False) {
return iter_.fail("bulk memory ops disabled");
}
#endif
return true;
}
bool BaseCompiler::emitMemCopy() {
if (!bulkmemOpsEnabled()) {
return false;
}
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
uint32_t dstMemOrTableIndex = 0;
@ -11972,10 +11957,6 @@ bool BaseCompiler::emitMemCopyInline() {
}
bool BaseCompiler::emitTableCopy() {
if (!bulkmemOpsEnabled()) {
return false;
}
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
uint32_t dstMemOrTableIndex = 0;
@ -12001,10 +11982,6 @@ bool BaseCompiler::emitTableCopy() {
}
bool BaseCompiler::emitDataOrElemDrop(bool isData) {
if (!bulkmemOpsEnabled()) {
return false;
}
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
uint32_t segIndex = 0;
@ -12025,10 +12002,6 @@ bool BaseCompiler::emitDataOrElemDrop(bool isData) {
}
bool BaseCompiler::emitMemFill() {
if (!bulkmemOpsEnabled()) {
return false;
}
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
Nothing nothing;
@ -12176,10 +12149,6 @@ bool BaseCompiler::emitMemFillInline() {
}
bool BaseCompiler::emitMemOrTableInit(bool isMem) {
if (!bulkmemOpsEnabled()) {
return false;
}
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
uint32_t segIndex = 0;

Просмотреть файл

@ -3481,13 +3481,6 @@ static bool EmitMemCopyInline(FunctionCompiler& f, MDefinition* dst,
}
static bool EmitMemCopy(FunctionCompiler& f) {
// Bulk memory must be available if shared memory is enabled.
#ifndef ENABLE_WASM_BULKMEM_OPS
if (f.env().sharedMemoryEnabled == Shareable::False) {
return f.iter().fail("bulk memory ops disabled");
}
#endif
MDefinition *dst, *src, *len;
uint32_t dstMemIndex;
uint32_t srcMemIndex;
@ -3509,13 +3502,6 @@ static bool EmitMemCopy(FunctionCompiler& f) {
}
static bool EmitTableCopy(FunctionCompiler& f) {
// Bulk memory must be available if shared memory is enabled.
#ifndef ENABLE_WASM_BULKMEM_OPS
if (f.env().sharedMemoryEnabled == Shareable::False) {
return f.iter().fail("bulk memory ops disabled");
}
#endif
MDefinition *dst, *src, *len;
uint32_t dstTableIndex;
uint32_t srcTableIndex;
@ -3567,13 +3553,6 @@ static bool EmitTableCopy(FunctionCompiler& f) {
}
static bool EmitDataOrElemDrop(FunctionCompiler& f, bool isData) {
// Bulk memory must be available if shared memory is enabled.
#ifndef ENABLE_WASM_BULKMEM_OPS
if (f.env().sharedMemoryEnabled == Shareable::False) {
return f.iter().fail("bulk memory ops disabled");
}
#endif
uint32_t segIndexVal = 0;
if (!f.iter().readDataOrElemDrop(isData, &segIndexVal)) {
return false;
@ -3714,13 +3693,6 @@ static bool EmitMemFillInline(FunctionCompiler& f, MDefinition* start,
}
static bool EmitMemFill(FunctionCompiler& f) {
// Bulk memory must be available if shared memory is enabled.
#ifndef ENABLE_WASM_BULKMEM_OPS
if (f.env().sharedMemoryEnabled == Shareable::False) {
return f.iter().fail("bulk memory ops disabled");
}
#endif
MDefinition *start, *val, *len;
if (!f.iter().readMemFill(&start, &val, &len)) {
return false;
@ -3740,13 +3712,6 @@ static bool EmitMemFill(FunctionCompiler& f) {
}
static bool EmitMemOrTableInit(FunctionCompiler& f, bool isMem) {
// Bulk memory must be available if shared memory is enabled.
#ifndef ENABLE_WASM_BULKMEM_OPS
if (f.env().sharedMemoryEnabled == Shareable::False) {
return f.iter().fail("bulk memory ops disabled");
}
#endif
uint32_t segIndexVal = 0, dstTableIndex = 0;
MDefinition *dstOff, *srcOff, *len;
if (!f.iter().readMemOrTableInit(isMem, &segIndexVal, &dstTableIndex, &dstOff,

Просмотреть файл

@ -543,58 +543,6 @@ bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
Instance& instance = instanceObj->instance();
const SharedTableVector& tables = instance.tables();
// Bulk memory changes the error checking behavior: we apply segments
// in-order and terminate if one has an out-of-bounds range.
// We enable bulk memory semantics if shared memory is enabled.
#ifdef ENABLE_WASM_BULKMEM_OPS
const bool eagerBoundsCheck = false;
#else
// Bulk memory must be available if shared memory is enabled.
const bool eagerBoundsCheck =
!cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
#endif
if (eagerBoundsCheck) {
// Perform all error checks up front so that this function does not perform
// partial initialization if an error is reported. In addition, we need to
// to report OOBs as a link error when bulk-memory is disabled.
for (const ElemSegment* seg : elemSegments_) {
if (!seg->active()) {
continue;
}
uint32_t tableLength = tables[seg->tableIndex]->length();
uint32_t offset =
EvaluateOffsetInitExpr(globalImportValues, seg->offset());
if (offset > tableLength || tableLength - offset < seg->length()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_FIT, "elem", "table");
return false;
}
}
if (memoryObj) {
uint32_t memoryLength = memoryObj->volatileMemoryLength();
for (const DataSegment* seg : dataSegments_) {
if (!seg->active()) {
continue;
}
uint32_t offset =
EvaluateOffsetInitExpr(globalImportValues, seg->offset());
if (offset > memoryLength ||
memoryLength - offset < seg->bytes.length()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_FIT, "data", "memory");
return false;
}
}
}
}
// Write data/elem segments into memories/tables.
for (const ElemSegment* seg : elemSegments_) {
@ -603,13 +551,11 @@ bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
EvaluateOffsetInitExpr(globalImportValues, seg->offset());
uint32_t count = seg->length();
if (!eagerBoundsCheck) {
uint32_t tableLength = tables[seg->tableIndex]->length();
if (offset > tableLength || tableLength - offset < count) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_OUT_OF_BOUNDS);
return false;
}
uint32_t tableLength = tables[seg->tableIndex]->length();
if (offset > tableLength || tableLength - offset < count) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_OUT_OF_BOUNDS);
return false;
}
if (!instance.initElems(seg->tableIndex, *seg, offset, 0, count)) {
@ -632,12 +578,10 @@ bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
EvaluateOffsetInitExpr(globalImportValues, seg->offset());
uint32_t count = seg->bytes.length();
if (!eagerBoundsCheck) {
if (offset > memoryLength || memoryLength - offset < count) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_OUT_OF_BOUNDS);
return false;
}
if (offset > memoryLength || memoryLength - offset < count) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_OUT_OF_BOUNDS);
return false;
}
memcpy(memoryBase + offset, seg->bytes.begin(), count);
}

Просмотреть файл

@ -1168,12 +1168,6 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
case uint32_t(MiscOp::I64TruncUSatF64):
CHECK(iter.readConversion(ValType::F64, ValType::I64, &nothing));
case uint32_t(MiscOp::MemCopy): {
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
uint32_t unusedDestMemIndex;
uint32_t unusedSrcMemIndex;
CHECK(iter.readMemOrTableCopy(/*isMem=*/true, &unusedDestMemIndex,
@ -1181,30 +1175,12 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
&nothing, &nothing));
}
case uint32_t(MiscOp::DataDrop): {
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
uint32_t unusedSegIndex;
CHECK(iter.readDataOrElemDrop(/*isData=*/true, &unusedSegIndex));
}
case uint32_t(MiscOp::MemFill):
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
CHECK(iter.readMemFill(&nothing, &nothing, &nothing));
case uint32_t(MiscOp::MemInit): {
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
uint32_t unusedSegIndex;
uint32_t unusedTableIndex;
CHECK(iter.readMemOrTableInit(/*isMem=*/true, &unusedSegIndex,
@ -1212,12 +1188,6 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
&nothing));
}
case uint32_t(MiscOp::TableCopy): {
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
uint32_t unusedDestTableIndex;
uint32_t unusedSrcTableIndex;
CHECK(iter.readMemOrTableCopy(
@ -1225,22 +1195,10 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
&unusedSrcTableIndex, &nothing, &nothing));
}
case uint32_t(MiscOp::ElemDrop): {
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
uint32_t unusedSegIndex;
CHECK(iter.readDataOrElemDrop(/*isData=*/false, &unusedSegIndex));
}
case uint32_t(MiscOp::TableInit): {
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env.sharedMemoryEnabled == Shareable::False) {
return iter.fail("bulk memory ops disabled");
}
#endif
uint32_t unusedSegIndex;
uint32_t unusedTableIndex;
CHECK(iter.readMemOrTableInit(/*isMem=*/false, &unusedSegIndex,
@ -2826,13 +2784,6 @@ static bool DecodeDataCountSection(Decoder& d, ModuleEnvironment* env) {
return true;
}
#ifndef ENABLE_WASM_BULKMEM_OPS
// Bulk memory must be available if shared memory is enabled.
if (env->sharedMemoryEnabled == Shareable::False) {
return d.fail("bulk memory ops disabled");
}
#endif
uint32_t dataCount;
if (!d.readVarU32(&dataCount)) {
return d.fail("expected data segment count");