Commit d8b0c1e3 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm][bulk] Update the element segment decoding to the new spec changes

The element segment encoding in the bulk memory proposal changed
recently. With this CL the V8 implementation gets up to date again.

R=thibaudm@chromium.org

Bug: v8:9658
Change-Id: I4f45d04369400356a6f3aaed9570c7870f5f97bd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1778022Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63836}
parent e92e8871
......@@ -797,9 +797,11 @@ class ModuleDecoderImpl : public Decoder {
const byte* pos = pc();
bool is_active;
bool functions_as_elements;
uint32_t table_index;
WasmInitExpr offset;
consume_segment_header("table index", &is_active, &table_index, &offset);
consume_element_segment_header(&is_active, &functions_as_elements,
&table_index, &offset);
if (failed()) return;
if (is_active) {
......@@ -814,12 +816,6 @@ class ModuleDecoderImpl : public Decoder {
table_index);
break;
}
} else {
ValueType type = consume_reference_type();
if (!ValueTypes::IsSubType(kWasmFuncRef, type)) {
error(pc_ - 1, "invalid element segment type");
break;
}
}
uint32_t num_elem =
......@@ -832,8 +828,8 @@ class ModuleDecoderImpl : public Decoder {
WasmElemSegment* init = &module_->elem_segments.back();
for (uint32_t j = 0; j < num_elem; j++) {
uint32_t index = is_active ? consume_element_func_index()
: consume_passive_element();
uint32_t index = functions_as_elements ? consume_element_expr()
: consume_element_func_index();
if (failed()) break;
init->entries.push_back(index);
}
......@@ -910,8 +906,7 @@ class ModuleDecoderImpl : public Decoder {
bool is_active;
uint32_t memory_index;
WasmInitExpr dest_addr;
consume_segment_header("memory index", &is_active, &memory_index,
&dest_addr);
consume_data_segment_header(&is_active, &memory_index, &dest_addr);
if (failed()) break;
if (is_active && memory_index != 0) {
......@@ -1681,8 +1676,103 @@ class ModuleDecoderImpl : public Decoder {
return attribute;
}
void consume_segment_header(const char* name, bool* is_active,
uint32_t* index, WasmInitExpr* offset) {
void consume_element_segment_header(bool* is_active,
bool* functions_as_elements,
uint32_t* table_index,
WasmInitExpr* offset) {
const byte* pos = pc();
uint8_t flag;
if (enabled_features_.bulk_memory || enabled_features_.anyref) {
flag = consume_u8("flag");
} else {
uint32_t table_index = consume_u32v("table index");
// The only valid flag value without bulk_memory or anyref is '0'.
if (table_index != 0) {
error(
"Element segments with table indices require "
"--experimental-wasm-bulk-memory or --experimental-wasm-anyref");
return;
}
flag = 0;
}
// The mask for the bit in the flag which indicates if the segment is
// active or not.
constexpr uint8_t kIsPassiveMask = 0x01;
// The mask for the bit in the flag which indicates if the segment has an
// explicit table index field.
constexpr uint8_t kHasTableIndexMask = 0x02;
// The mask for the bit in the flag which indicates if the functions of this
// segment are defined as function indices (=0) or elements(=1).
constexpr uint8_t kFunctionsAsElementsMask = 0x04;
constexpr uint8_t kFullMask =
kIsPassiveMask | kHasTableIndexMask | kFunctionsAsElementsMask;
bool is_passive = flag & kIsPassiveMask;
*is_active = !is_passive;
*functions_as_elements = flag & kFunctionsAsElementsMask;
bool has_table_index = flag & kHasTableIndexMask;
if (is_passive && !enabled_features_.bulk_memory) {
error("Passive element segments require --experimental-wasm-bulk-memory");
return;
}
if (*functions_as_elements && !enabled_features_.bulk_memory) {
error(
"Illegal segment flag. Did you forget "
"--experimental-wasm-bulk-memory?");
return;
}
if (flag != 0 && !enabled_features_.bulk_memory &&
!enabled_features_.anyref) {
error(
"Invalid segment flag. Did you forget "
"--experimental-wasm-bulk-memory or --experimental-wasm-anyref?");
return;
}
if ((flag & kFullMask) != flag || (!(*is_active) && has_table_index)) {
errorf(pos, "illegal flag value %u. Must be 0, 1, 2, 4, 5 or 6", flag);
}
if (has_table_index) {
*table_index = consume_u32v("table index");
} else {
*table_index = 0;
}
if (*is_active) {
*offset = consume_init_expr(module_.get(), kWasmI32);
}
if (*is_active && !has_table_index) {
// Active segments without table indices are a special case for backwards
// compatibility. These cases have an implicit element kind or element
// type, so we are done already with the segment header.
return;
}
if (*functions_as_elements) {
// We have to check that there is an element type of type FuncRef. All
// other element types are not valid yet.
ValueType type = consume_reference_type();
if (!ValueTypes::IsSubType(kWasmFuncRef, type)) {
error(pc_ - 1, "invalid element segment type");
return;
}
} else {
// We have to check that there is an element kind of type Function. All
// other element kinds are not valid yet.
uint8_t val = consume_u8("element kind");
ImportExportKindCode kind = static_cast<ImportExportKindCode>(val);
if (kind != kExternalFunction) {
errorf(pos, "illegal element kind %x. Must be 0x00", val);
return;
}
}
}
void consume_data_segment_header(bool* is_active, uint32_t* index,
WasmInitExpr* offset) {
const byte* pos = pc();
uint32_t flag = consume_u32v("flag");
......@@ -1718,7 +1808,7 @@ class ModuleDecoderImpl : public Decoder {
}
if (flag == SegmentFlags::kActiveWithIndex) {
*is_active = true;
*index = consume_u32v(name);
*index = consume_u32v("memory index");
*offset = consume_init_expr(module_.get(), kWasmI32);
}
}
......@@ -1734,7 +1824,7 @@ class ModuleDecoderImpl : public Decoder {
return index;
}
uint32_t consume_passive_element() {
uint32_t consume_element_expr() {
uint32_t index = WasmElemSegment::kNullIndex;
uint8_t opcode = consume_u8("element opcode");
if (failed()) return index;
......
......@@ -27,12 +27,14 @@
#define ACTIVE_NO_INDEX 0
#define PASSIVE 1
#define ACTIVE_WITH_INDEX 2
#define PASSIVE_WITH_ELEMENTS 5
#define ACTIVE_WITH_ELEMENTS 6
// 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 TABLE_INDEX0 static_cast<byte>(ACTIVE_NO_INDEX)
#define TABLE_INDEX(v) static_cast<byte>(ACTIVE_WITH_INDEX), U32V_1(v)
#define ZERO_ALIGNMENT 0
#define ZERO_OFFSET 0
......
......@@ -84,6 +84,7 @@ let kSharedHasMaximumFlag = 3;
let kActiveNoIndex = 0;
let kPassive = 1;
let kActiveWithIndex = 2;
let kPassiveWithElements = 5;
// Function declaration flags
let kDeclFunctionName = 0x01;
......@@ -1164,13 +1165,16 @@ class WasmModuleBuilder {
}
section.emit_u32v(init.base);
section.emit_u8(kExprEnd);
if (init.table != 0) {
section.emit_u8(kExternalFunction);
}
section.emit_u32v(init.array.length);
for (let index of init.array) {
section.emit_u32v(index);
}
} else {
// Passive segment.
section.emit_u8(kPassive); // flags
section.emit_u8(kPassiveWithElements); // flags
section.emit_u8(kWasmAnyFunc);
section.emit_u32v(init.array.length);
for (let index of init.array) {
......
......@@ -1086,6 +1086,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
FUNC_INDEX(0), // function
TABLE_INDEX(1), // element for table 1
WASM_INIT_EXPR_I32V_1(7), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
......@@ -1132,15 +1133,18 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
FUNC_INDEX(0), // function
TABLE_INDEX(1), // element for table 1
WASM_INIT_EXPR_I32V_1(7), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0), // entry 1
TABLE_INDEX(2), // element for table 2
WASM_INIT_EXPR_I32V_1(12), // index
kExternalFunction, // type
1, // elements count
FUNC_INDEX(0), // function
TABLE_INDEX(3), // element for table 1
WASM_INIT_EXPR_I32V_1(17), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
......@@ -1173,6 +1177,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
FUNC_INDEX(0), // function
TABLE_INDEX(1), // element for table 0
WASM_INIT_EXPR_I32V_1(7), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0), // entry 1
......@@ -1219,10 +1224,12 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
4, // entry count
TABLE_INDEX(2), // element for table 0
WASM_INIT_EXPR_I32V_1(10), // index
kExternalFunction, // type
1, // elements count
FUNC_INDEX(0), // function
TABLE_INDEX(3), // element for table 1
WASM_INIT_EXPR_I32V_1(17), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0), // entry 1
......@@ -1232,6 +1239,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
FUNC_INDEX(0), // function
TABLE_INDEX(1), // element for table 1
WASM_INIT_EXPR_I32V_1(7), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
......@@ -1262,6 +1270,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionInitAnyRefTableWithFuncRef) {
FUNC_INDEX(0), // function
TABLE_INDEX(1), // element for table 1
WASM_INIT_EXPR_I32V_1(7), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
......@@ -1309,6 +1318,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
FUNC_INDEX(0), // function
TABLE_INDEX(1), // element for table 1
WASM_INIT_EXPR_I32V_1(17), // index
kExternalFunction, // type
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
......@@ -2359,7 +2369,7 @@ TEST_F(WasmModuleVerifyTest, PassiveDataSegment) {
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
}
TEST_F(WasmModuleVerifyTest, PassiveElementSegment) {
TEST_F(WasmModuleVerifyTest, ActiveElementSegmentWithElements) {
static const byte data[] = {
// sig#0 -----------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
......@@ -2368,7 +2378,8 @@ TEST_F(WasmModuleVerifyTest, PassiveElementSegment) {
// table declaration -----------------------------------------------------
SECTION(Table, ENTRY_COUNT(1), kLocalFuncRef, 0, 1),
// element segments -----------------------------------------------------
SECTION(Element, ENTRY_COUNT(1), PASSIVE, kLocalFuncRef, U32V_1(3),
SECTION(Element, ENTRY_COUNT(1), ACTIVE_WITH_ELEMENTS, TABLE_INDEX0,
WASM_INIT_EXPR_I32V_1(0), kLocalFuncRef, U32V_1(3),
REF_FUNC_ELEMENT(0), REF_FUNC_ELEMENT(0), REF_NULL_ELEMENT),
// code ------------------------------------------------------------------
ONE_EMPTY_BODY};
......@@ -2378,6 +2389,26 @@ TEST_F(WasmModuleVerifyTest, PassiveElementSegment) {
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), kLocalFuncRef, 0, 1),
// element segments -----------------------------------------------------
SECTION(Element, ENTRY_COUNT(1), PASSIVE_WITH_ELEMENTS, kLocalFuncRef,
U32V_1(3), REF_FUNC_ELEMENT(0), REF_FUNC_ELEMENT(0),
REF_NULL_ELEMENT),
// code ------------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_FAILURE(data);
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(data);
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
}
TEST_F(WasmModuleVerifyTest, PassiveElementSegmentAnyRef) {
static const byte data[] = {
// sig#0 -----------------------------------------------------------------
......@@ -2387,13 +2418,33 @@ TEST_F(WasmModuleVerifyTest, PassiveElementSegmentAnyRef) {
// table declaration -----------------------------------------------------
SECTION(Table, ENTRY_COUNT(1), kLocalFuncRef, 0, 1),
// element segments -----------------------------------------------------
SECTION(Element, ENTRY_COUNT(1), PASSIVE, kLocalAnyRef, U32V_1(0)),
SECTION(Element, ENTRY_COUNT(1), PASSIVE_WITH_ELEMENTS, kLocalAnyRef,
U32V_1(0)),
// code ------------------------------------------------------------------
ONE_EMPTY_BODY};
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, PassiveElementSegmentWithIndices) {
static const byte data[] = {
// sig#0 -----------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
// funcs -----------------------------------------------------------------
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
// table declaration -----------------------------------------------------
SECTION(Table, ENTRY_COUNT(1), kLocalFuncRef, 0, 1),
// element segments -----------------------------------------------------
SECTION(Element, ENTRY_COUNT(1), PASSIVE, kExternalFunction,
ENTRY_COUNT(3), U32V_1(0), U32V_1(0), U32V_1(0)),
// code ------------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_FAILURE(data);
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(data);
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5);
}
TEST_F(WasmModuleVerifyTest, DataCountSectionCorrectPlacement) {
static const byte data[] = {SECTION(Element, ENTRY_COUNT(0)),
SECTION(DataCount, ENTRY_COUNT(0)),
......
1e0e2435efac858f3269de548d7c795fb6173ca8
\ No newline at end of file
2ecf4038f24fc08bd9da504f15942d3abb5ec685
\ No newline at end of file
088e8722b3fe99ea3a67a9852e787f461f348d0b
\ No newline at end of file
f9bd936c708402051f87f4ac8940d1916112a15a
\ No newline at end of file
......@@ -10,15 +10,9 @@
# the bulk-memory proposal. Since we've enabled bulk-memory by default, we
# need to update to use its testsuite.
'linking': [FAIL],
'binary-leb128': [FAIL],
'elem': [FAIL],
'data': [FAIL],
# TODO(v8:9658): The encoding of element segments changed in the bulk memory
# proposal
'proposals/bulk-memory-operations/bulk': [FAIL],
'proposals/bulk-memory-operations/table_init': [FAIL],
'proposals/bulk-memory-operations/table_copy': [FAIL],
'proposals/bulk-memory-operations/elem': [FAIL],
'proposals/bulk-memory-operations/binary': [FAIL],
# TODO(mstarzinger): Roll newest tests into "js-types" repository.
'proposals/js-types/exports': [FAIL],
'proposals/js-types/globals': [FAIL],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment