[wasm] Add bulk memory flag; parse passive segments
See the WebAssembly bulk memory proposal here: https://github.com/WebAssembly/bulk-memory-operations This initial CL adds a wasm experimental flag: `--experimental-wasm-bulk-memory`, and also parsing of passive segments. A passive segment is one that is not copied into the table/memory on instantiation, but instead later via the `{table,memory}.init` instructions. The binary format of passive data segments is unlikely to change, but the format for passive element segments may change (see https://github.com/WebAssembly/bulk-memory-operations/pull/39). Bug: v8:7747 Change-Id: I2a7fb9bc7648a722a8c4aab4185c68d3d0843858 Reviewed-on: https://chromium-review.googlesource.com/c/1330015 Commit-Queue: Ben Smith <binji@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#57451}
This commit is contained in:
parent
8974fa04db
commit
fd1b8bbf9e
@ -1257,6 +1257,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
// Check that indirect function table segments are within bounds.
|
||||
//--------------------------------------------------------------------------
|
||||
for (const WasmTableInit& table_init : module_->table_inits) {
|
||||
if (!table_init.active) continue;
|
||||
DCHECK(table_init.table_index < table_instances_.size());
|
||||
uint32_t base = EvalUint32InitExpr(table_init.offset);
|
||||
size_t table_size = table_instances_[table_init.table_index].table_size;
|
||||
@ -1270,6 +1271,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
// Check that memory segments are within bounds.
|
||||
//--------------------------------------------------------------------------
|
||||
for (const WasmDataSegment& seg : module_->data_segments) {
|
||||
if (!seg.active) continue;
|
||||
uint32_t base = EvalUint32InitExpr(seg.dest_addr);
|
||||
if (!in_bounds(base, seg.source.length(), instance->memory_size())) {
|
||||
thrower_->LinkError("data segment is out of bounds");
|
||||
@ -1449,6 +1451,8 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
|
||||
uint32_t source_size = segment.source.length();
|
||||
// Segments of size == 0 are just nops.
|
||||
if (source_size == 0) continue;
|
||||
// Passive segments are not copied during instantiation.
|
||||
if (!segment.active) continue;
|
||||
uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
|
||||
DCHECK(in_bounds(dest_offset, source_size, instance->memory_size()));
|
||||
byte* dest = instance->memory_start() + dest_offset;
|
||||
@ -2192,6 +2196,9 @@ void InstanceBuilder::InitializeTables(Handle<WasmInstanceObject> instance) {
|
||||
void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
|
||||
NativeModule* native_module = module_object_->native_module();
|
||||
for (auto& table_init : module_->table_inits) {
|
||||
// Passive segments are not copied during instantiation.
|
||||
if (!table_init.active) continue;
|
||||
|
||||
uint32_t base = EvalUint32InitExpr(table_init.offset);
|
||||
uint32_t num_entries = static_cast<uint32_t>(table_init.entries.size());
|
||||
uint32_t index = table_init.table_index;
|
||||
|
@ -753,23 +753,34 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
for (uint32_t i = 0; ok() && i < element_count; ++i) {
|
||||
const byte* pos = pc();
|
||||
uint32_t table_index = consume_u32v("table index");
|
||||
if (!enabled_features_.anyref && table_index != 0) {
|
||||
errorf(pos, "illegal table index %u != 0", table_index);
|
||||
|
||||
bool is_active;
|
||||
uint32_t table_index;
|
||||
WasmInitExpr offset;
|
||||
consume_segment_header("table index", &is_active, &table_index, &offset);
|
||||
if (failed()) return;
|
||||
|
||||
if (is_active) {
|
||||
if (table_index >= module_->tables.size()) {
|
||||
errorf(pos, "out of bounds table index %u", table_index);
|
||||
break;
|
||||
}
|
||||
if (module_->tables[table_index].type != kWasmAnyFunc) {
|
||||
errorf(pos,
|
||||
"Invalid element segment. Table %u is not of type AnyFunc",
|
||||
table_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (table_index >= module_->tables.size()) {
|
||||
errorf(pos, "out of bounds table index %u", table_index);
|
||||
break;
|
||||
}
|
||||
if (module_->tables[table_index].type != kWasmAnyFunc) {
|
||||
errorf(pos, "Invalid element segment. Table %u is not of type AnyFunc",
|
||||
table_index);
|
||||
break;
|
||||
}
|
||||
WasmInitExpr offset = consume_init_expr(module_.get(), kWasmI32);
|
||||
|
||||
uint32_t num_elem =
|
||||
consume_count("number of elements", kV8MaxWasmTableEntries);
|
||||
module_->table_inits.emplace_back(table_index, offset);
|
||||
if (is_active) {
|
||||
module_->table_inits.emplace_back(table_index, offset);
|
||||
} else {
|
||||
module_->table_inits.emplace_back();
|
||||
}
|
||||
|
||||
WasmTableInit* init = &module_->table_inits.back();
|
||||
for (uint32_t j = 0; j < num_elem; j++) {
|
||||
WasmFunction* func = nullptr;
|
||||
@ -829,18 +840,41 @@ class ModuleDecoderImpl : public Decoder {
|
||||
consume_count("data segments count", kV8MaxWasmDataSegments);
|
||||
module_->data_segments.reserve(data_segments_count);
|
||||
for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
|
||||
const byte* pos = pc();
|
||||
if (!module_->has_memory) {
|
||||
error("cannot load data without memory");
|
||||
break;
|
||||
}
|
||||
TRACE("DecodeDataSegment[%d] module+%d\n", i,
|
||||
static_cast<int>(pc_ - start_));
|
||||
module_->data_segments.push_back({
|
||||
WasmInitExpr(), // dest_addr
|
||||
{0, 0} // source
|
||||
});
|
||||
|
||||
bool is_active;
|
||||
uint32_t memory_index;
|
||||
WasmInitExpr dest_addr;
|
||||
consume_segment_header("memory index", &is_active, &memory_index,
|
||||
&dest_addr);
|
||||
if (failed()) break;
|
||||
|
||||
if (is_active && memory_index != 0) {
|
||||
errorf(pos, "illegal memory index %u != 0", memory_index);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t source_length = consume_u32v("source size");
|
||||
uint32_t source_offset = pc_offset();
|
||||
|
||||
if (is_active) {
|
||||
module_->data_segments.emplace_back(dest_addr);
|
||||
} else {
|
||||
module_->data_segments.emplace_back();
|
||||
}
|
||||
|
||||
WasmDataSegment* segment = &module_->data_segments.back();
|
||||
DecodeDataSegmentInModule(module_.get(), segment);
|
||||
|
||||
consume_bytes(source_length, "segment data");
|
||||
if (failed()) break;
|
||||
|
||||
segment->source = {source_offset, source_length};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1069,17 +1103,6 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
|
||||
// Decodes a single data segment entry inside a module starting at {pc_}.
|
||||
void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
|
||||
expect_u8("linear memory index", 0);
|
||||
segment->dest_addr = consume_init_expr(module, kWasmI32);
|
||||
uint32_t source_length = consume_u32v("source size");
|
||||
uint32_t source_offset = pc_offset();
|
||||
|
||||
consume_bytes(source_length, "segment data");
|
||||
if (failed()) return;
|
||||
|
||||
segment->source = {source_offset, source_length};
|
||||
}
|
||||
|
||||
// Calculate individual global offsets and total size of globals table.
|
||||
void CalculateGlobalOffsets(WasmModule* module) {
|
||||
@ -1465,6 +1488,55 @@ class ModuleDecoderImpl : public Decoder {
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
|
||||
void consume_segment_header(const char* name, bool* is_active,
|
||||
uint32_t* index, WasmInitExpr* offset) {
|
||||
const byte* pos = pc();
|
||||
// In the MVP, this is a table or memory index field that must be 0, but
|
||||
// we've repurposed it as a flags field in the bulk memory proposal.
|
||||
uint32_t flags;
|
||||
if (enabled_features_.bulk_memory) {
|
||||
flags = consume_u32v("flags");
|
||||
if (failed()) return;
|
||||
} else {
|
||||
flags = consume_u32v(name);
|
||||
if (failed()) return;
|
||||
|
||||
if (flags != 0) {
|
||||
errorf(pos, "illegal %s %u != 0", name, flags);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool read_index;
|
||||
bool read_offset;
|
||||
if (flags == SegmentFlags::kActiveNoIndex) {
|
||||
*is_active = true;
|
||||
read_index = false;
|
||||
read_offset = true;
|
||||
} else if (flags == SegmentFlags::kPassive) {
|
||||
*is_active = false;
|
||||
read_index = false;
|
||||
read_offset = false;
|
||||
} else if (flags == SegmentFlags::kActiveWithIndex) {
|
||||
*is_active = true;
|
||||
read_index = true;
|
||||
read_offset = true;
|
||||
} else {
|
||||
errorf(pos, "illegal flag value %u. Must be 0, 1, or 2", flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_index) {
|
||||
*index = consume_u32v(name);
|
||||
} else {
|
||||
*index = 0;
|
||||
}
|
||||
|
||||
if (read_offset) {
|
||||
*offset = consume_init_expr(module_.get(), kWasmI32);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
|
||||
|
@ -50,6 +50,13 @@ enum MemoryFlags : uint8_t {
|
||||
kSharedAndMaximum = 3
|
||||
};
|
||||
|
||||
// Flags for data and element segments.
|
||||
enum SegmentFlags : uint8_t {
|
||||
kActiveNoIndex = 0, // Active segment with a memory/table index of zero.
|
||||
kPassive = 1, // Passive segment.
|
||||
kActiveWithIndex = 2, // Active segment with a given memory/table index.
|
||||
};
|
||||
|
||||
// Binary encoding of sections identifiers.
|
||||
enum SectionCode : int8_t {
|
||||
kUnknownSectionCode = 0, // code for unknown sections
|
||||
|
@ -21,6 +21,8 @@
|
||||
SEPARATOR \
|
||||
V(anyref, "anyref opcodes", false) \
|
||||
SEPARATOR \
|
||||
V(mut_global, "import/export mutable global support", true)
|
||||
V(mut_global, "import/export mutable global support", true) \
|
||||
SEPARATOR \
|
||||
V(bulk_memory, "bulk memory opcodes", false)
|
||||
|
||||
#endif // V8_WASM_WASM_FEATURE_FLAGS_H_
|
||||
|
@ -84,8 +84,16 @@ struct WasmException {
|
||||
|
||||
// Static representation of a wasm data segment.
|
||||
struct WasmDataSegment {
|
||||
// Construct an active segment.
|
||||
explicit WasmDataSegment(WasmInitExpr dest_addr)
|
||||
: dest_addr(dest_addr), active(true) {}
|
||||
|
||||
// Construct a passive segment, which has no dest_addr.
|
||||
WasmDataSegment() : active(false) {}
|
||||
|
||||
WasmInitExpr dest_addr; // destination memory address of the data.
|
||||
WireBytesRef source; // start offset in the module bytes.
|
||||
bool active = true; // true if copied automatically during instantiation.
|
||||
};
|
||||
|
||||
// Static representation of a wasm indirect call table.
|
||||
@ -105,12 +113,17 @@ struct WasmTable {
|
||||
struct WasmTableInit {
|
||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmTableInit);
|
||||
|
||||
// Construct an active segment.
|
||||
WasmTableInit(uint32_t table_index, WasmInitExpr offset)
|
||||
: table_index(table_index), offset(offset) {}
|
||||
: table_index(table_index), offset(offset), active(true) {}
|
||||
|
||||
// Construct a passive segment, which has no table index or offset.
|
||||
WasmTableInit() : table_index(0), active(false) {}
|
||||
|
||||
uint32_t table_index;
|
||||
WasmInitExpr offset;
|
||||
std::vector<uint32_t> entries;
|
||||
bool active; // true if copied automatically during instantiation.
|
||||
};
|
||||
|
||||
// Static representation of a wasm import.
|
||||
|
@ -19,11 +19,21 @@
|
||||
|
||||
#define SIG_INDEX(v) U32V_1(v)
|
||||
#define FUNC_INDEX(v) U32V_1(v)
|
||||
#define TABLE_INDEX(v) U32V_1(v)
|
||||
#define EXCEPTION_INDEX(v) U32V_1(v)
|
||||
#define NO_NAME U32V_1(0)
|
||||
#define ENTRY_COUNT(v) U32V_1(v)
|
||||
|
||||
// Segment flags
|
||||
#define ACTIVE_NO_INDEX 0
|
||||
#define PASSIVE 1
|
||||
#define ACTIVE_WITH_INDEX 2
|
||||
|
||||
// The table index field in an element segment was repurposed as a flags field.
|
||||
// To specify a table index, we have to set the flag value to 2, followed by
|
||||
// the table index.
|
||||
#define TABLE_INDEX0 U32V_1(ACTIVE_NO_INDEX)
|
||||
#define TABLE_INDEX(v) U32V_1(ACTIVE_WITH_INDEX), U32V_1(v)
|
||||
|
||||
#define ZERO_ALIGNMENT 0
|
||||
#define ZERO_OFFSET 0
|
||||
|
||||
|
29
test/mjsunit/wasm/bulk-memory.js
Normal file
29
test/mjsunit/wasm/bulk-memory.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --experimental-wasm-bulk-memory
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function TestPassiveDataSegment() {
|
||||
const builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
builder.addPassiveDataSegment([0, 1, 2]);
|
||||
builder.addPassiveDataSegment([3, 4]);
|
||||
|
||||
// Should not throw.
|
||||
const module = builder.instantiate();
|
||||
})();
|
||||
|
||||
(function TestPassiveElementSegment() {
|
||||
const builder = new WasmModuleBuilder();
|
||||
builder.addFunction('f', kSig_v_v).addBody([]);
|
||||
builder.setTableLength(1);
|
||||
builder.addPassiveElementSegment([0, 0, 0]);
|
||||
builder.addPassiveElementSegment([0, 0]);
|
||||
|
||||
// Should not throw.
|
||||
const module = builder.instantiate();
|
||||
})();
|
@ -77,6 +77,11 @@ let kWasmAnyFunctionTypeForm = 0x70;
|
||||
|
||||
let kHasMaximumFlag = 1;
|
||||
|
||||
// Segment flags
|
||||
let kActiveNoIndex = 0;
|
||||
let kPassive = 1;
|
||||
let kActiveWithIndex = 2;
|
||||
|
||||
// Function declaration flags
|
||||
let kDeclFunctionName = 0x01;
|
||||
let kDeclFunctionImport = 0x02;
|
||||
|
@ -299,7 +299,13 @@ class WasmModuleBuilder {
|
||||
}
|
||||
|
||||
addDataSegment(addr, data, is_global = false) {
|
||||
this.data_segments.push({addr: addr, data: data, is_global: is_global});
|
||||
this.data_segments.push(
|
||||
{addr: addr, data: data, is_global: is_global, is_active: true});
|
||||
return this.data_segments.length - 1;
|
||||
}
|
||||
|
||||
addPassiveDataSegment(data) {
|
||||
this.data_segments.push({data: data, is_active: false});
|
||||
return this.data_segments.length - 1;
|
||||
}
|
||||
|
||||
@ -309,7 +315,7 @@ class WasmModuleBuilder {
|
||||
|
||||
addElementSegment(base, is_global, array, is_import = false) {
|
||||
this.element_segments.push({base: base, is_global: is_global,
|
||||
array: array});
|
||||
array: array, is_active: true});
|
||||
if (!is_global) {
|
||||
var length = base + array.length;
|
||||
if (length > this.table_length_min && !is_import) {
|
||||
@ -322,6 +328,11 @@ class WasmModuleBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
addPassiveElementSegment(array, is_import = false) {
|
||||
this.element_segments.push({array: array, is_active: false});
|
||||
return this;
|
||||
}
|
||||
|
||||
appendToTable(array) {
|
||||
for (let n of array) {
|
||||
if (typeof n != 'number')
|
||||
@ -554,14 +565,18 @@ class WasmModuleBuilder {
|
||||
section.emit_u32v(inits.length);
|
||||
|
||||
for (let init of inits) {
|
||||
section.emit_u8(0); // table index
|
||||
if (init.is_global) {
|
||||
section.emit_u8(kExprGetGlobal);
|
||||
if (init.is_active) {
|
||||
section.emit_u8(0); // table index / flags
|
||||
if (init.is_global) {
|
||||
section.emit_u8(kExprGetGlobal);
|
||||
} else {
|
||||
section.emit_u8(kExprI32Const);
|
||||
}
|
||||
section.emit_u32v(init.base);
|
||||
section.emit_u8(kExprEnd);
|
||||
} else {
|
||||
section.emit_u8(kExprI32Const);
|
||||
section.emit_u8(kPassive); // flags
|
||||
}
|
||||
section.emit_u32v(init.base);
|
||||
section.emit_u8(kExprEnd);
|
||||
section.emit_u32v(init.array.length);
|
||||
for (let index of init.array) {
|
||||
section.emit_u32v(index);
|
||||
@ -623,17 +638,21 @@ class WasmModuleBuilder {
|
||||
binary.emit_section(kDataSectionCode, section => {
|
||||
section.emit_u32v(wasm.data_segments.length);
|
||||
for (let seg of wasm.data_segments) {
|
||||
section.emit_u8(0); // linear memory index 0
|
||||
if (seg.is_global) {
|
||||
// initializer is a global variable
|
||||
section.emit_u8(kExprGetGlobal);
|
||||
section.emit_u32v(seg.addr);
|
||||
if (seg.is_active) {
|
||||
section.emit_u8(0); // linear memory index 0 / flags
|
||||
if (seg.is_global) {
|
||||
// initializer is a global variable
|
||||
section.emit_u8(kExprGetGlobal);
|
||||
section.emit_u32v(seg.addr);
|
||||
} else {
|
||||
// initializer is a constant
|
||||
section.emit_u8(kExprI32Const);
|
||||
section.emit_u32v(seg.addr);
|
||||
}
|
||||
section.emit_u8(kExprEnd);
|
||||
} else {
|
||||
// initializer is a constant
|
||||
section.emit_u8(kExprI32Const);
|
||||
section.emit_u32v(seg.addr);
|
||||
section.emit_u8(kPassive); // flags
|
||||
}
|
||||
section.emit_u8(kExprEnd);
|
||||
section.emit_u32v(seg.data.length);
|
||||
section.emit_bytes(seg.data);
|
||||
}
|
||||
|
@ -912,7 +912,7 @@ TEST_F(WasmModuleVerifyTest, Regression_735887) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(1), // entry count
|
||||
TABLE_INDEX(0), WASM_INIT_EXPR_I32V_1(0),
|
||||
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
|
||||
1, // elements count
|
||||
0x9A) // invalid I32V as function index
|
||||
};
|
||||
@ -931,7 +931,7 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction_one_entry) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(1), // entry count
|
||||
TABLE_INDEX(0), WASM_INIT_EXPR_I32V_1(0),
|
||||
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
|
||||
1, // elements count
|
||||
FUNC_INDEX(0))};
|
||||
|
||||
@ -957,7 +957,7 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
||||
// table elements ----------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(1), // entry count
|
||||
TABLE_INDEX(0), WASM_INIT_EXPR_I32V_1(0),
|
||||
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
|
||||
ADD_COUNT(FUNC_INDEX(0), FUNC_INDEX(1), FUNC_INDEX(2),
|
||||
FUNC_INDEX(3), FUNC_INDEX(0), FUNC_INDEX(1),
|
||||
FUNC_INDEX(2), FUNC_INDEX(3))),
|
||||
@ -975,6 +975,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
|
||||
// Test that if we have multiple tables, in the element section we can target
|
||||
// and initialize all tables.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
static const byte data[] = {
|
||||
// sig#0 ---------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
@ -987,7 +988,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(2), // entry count
|
||||
TABLE_INDEX(0), // element for table 0
|
||||
TABLE_INDEX0, // element for table 0
|
||||
WASM_INIT_EXPR_I32V_1(0), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0), // function
|
||||
@ -1005,6 +1006,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
|
||||
// Test that if we have multiple tables, both imported and module-defined, in
|
||||
// the element section we can target and initialize all tables.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
static const byte data[] = {
|
||||
// sig#0 ---------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
@ -1031,7 +1033,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
4, // entry count
|
||||
TABLE_INDEX(0), // element for table 0
|
||||
TABLE_INDEX0, // element for table 0
|
||||
WASM_INIT_EXPR_I32V_1(0), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0), // function
|
||||
@ -1058,6 +1060,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
||||
// Test that the order in which tables are targeted in the element secion
|
||||
// can be arbitrary.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
static const byte data[] = {
|
||||
// sig#0 ---------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
@ -1070,7 +1073,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(3), // entry count
|
||||
TABLE_INDEX(0), // element for table 1
|
||||
TABLE_INDEX0, // element for table 1
|
||||
WASM_INIT_EXPR_I32V_1(0), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0), // function
|
||||
@ -1079,7 +1082,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
||||
2, // elements count
|
||||
FUNC_INDEX(0), // entry 0
|
||||
FUNC_INDEX(0), // entry 1
|
||||
TABLE_INDEX(0), // element for table 1
|
||||
TABLE_INDEX0, // element for table 1
|
||||
WASM_INIT_EXPR_I32V_1(3), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0)), // function
|
||||
@ -1092,6 +1095,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
||||
// Test that the order in which tables are targeted in the element secion can
|
||||
// be arbitrary. In this test, tables can be both imported and module-defined.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
static const byte data[] = {
|
||||
// sig#0 ---------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
@ -1127,7 +1131,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
||||
2, // elements count
|
||||
FUNC_INDEX(0), // entry 0
|
||||
FUNC_INDEX(0), // entry 1
|
||||
TABLE_INDEX(0), // element for table 2
|
||||
TABLE_INDEX0, // element for table 2
|
||||
WASM_INIT_EXPR_I32V_1(2), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0), // function
|
||||
@ -1145,6 +1149,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
||||
// Test that tables of type 'AnyRef' cannot be initialized by the element
|
||||
// section.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
static const byte data[] = {
|
||||
// sig#0 ---------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
@ -1157,7 +1162,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(2), // entry count
|
||||
TABLE_INDEX(0), // element for table 0
|
||||
TABLE_INDEX0, // element for table 0
|
||||
WASM_INIT_EXPR_I32V_1(0), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0), // function
|
||||
@ -1175,6 +1180,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
|
||||
// Test that imported tables of type AnyRef cannot be initialized in the
|
||||
// elements section.
|
||||
WASM_FEATURE_SCOPE(anyref);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
static const byte data[] = {
|
||||
// sig#0 ---------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
@ -1201,7 +1207,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
|
||||
// elements ------------------------------------------------------------
|
||||
SECTION(Element,
|
||||
ENTRY_COUNT(4), // entry count
|
||||
TABLE_INDEX(0), // element for table 0
|
||||
TABLE_INDEX0, // element for table 0
|
||||
WASM_INIT_EXPR_I32V_1(10), // index
|
||||
1, // elements count
|
||||
FUNC_INDEX(0), // function
|
||||
@ -2201,6 +2207,37 @@ TEST_F(WasmModuleVerifyTest, MultipleNameSections) {
|
||||
EXPECT_EQ(3u, result.value()->name.length());
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, PassiveDataSegment) {
|
||||
static const byte data[] = {
|
||||
// memory declaration ----------------------------------------------------
|
||||
SECTION(Memory, ENTRY_COUNT(1), 0, 1),
|
||||
// data segments --------------------------------------------------------
|
||||
SECTION(Data, ENTRY_COUNT(1), PASSIVE, ADD_COUNT('h', 'i')),
|
||||
};
|
||||
EXPECT_FAILURE(data);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
EXPECT_VERIFIES(data);
|
||||
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, PassiveElementSegment) {
|
||||
static const byte data[] = {
|
||||
// sig#0 -----------------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
// funcs -----------------------------------------------------------------
|
||||
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
|
||||
// table declaration -----------------------------------------------------
|
||||
SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1),
|
||||
// element segments -----------------------------------------------------
|
||||
SECTION(Element, ENTRY_COUNT(1), PASSIVE,
|
||||
ADD_COUNT(FUNC_INDEX(0), FUNC_INDEX(0))),
|
||||
};
|
||||
EXPECT_FAILURE(data);
|
||||
WASM_FEATURE_SCOPE(bulk_memory);
|
||||
EXPECT_VERIFIES(data);
|
||||
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
|
||||
}
|
||||
|
||||
#undef WASM_FEATURE_SCOPE
|
||||
#undef WASM_FEATURE_SCOPE_VAL
|
||||
#undef EXPECT_INIT_EXPR
|
||||
|
Loading…
Reference in New Issue
Block a user