Skip to content

Commit 0ec54cb

Browse files
authored
Update testsuite (#2054)
As well as the testsuite update there are two notable changes that come with it here. These can both be split out an landed first if it makes sense. 1. wasm2c now supports element sections containing externref. Currently only the null reference is supported. 2. element segments no longer use funcref as the default element type but instead, unless explicitly included in the binary, the element type defaults to the type of the table in which the segment is active. Fixes: #1612 #2022
1 parent a3c6ec4 commit 0ec54cb

File tree

25 files changed

+465
-324
lines changed

25 files changed

+465
-324
lines changed

include/wabt/shared-validator.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class SharedValidator {
8888
Result OnStart(const Location&, Var func_var);
8989

9090
Result OnElemSegment(const Location&, Var table_var, SegmentKind);
91-
void OnElemSegmentElemType(Type elem_type);
91+
Result OnElemSegmentElemType(const Location&, Type elem_type);
9292
Result OnElemSegmentElemExpr_RefNull(const Location&, Type type);
9393
Result OnElemSegmentElemExpr_RefFunc(const Location&, Var func_var);
9494
Result OnElemSegmentElemExpr_Other(const Location&);
@@ -236,9 +236,12 @@ class SharedValidator {
236236

237237
struct ElemType {
238238
ElemType() = default;
239-
ElemType(Type element) : element(element) {}
239+
ElemType(Type element, bool is_active, Type table_type)
240+
: element(element), is_active(is_active), table_type(table_type) {}
240241

241242
Type element;
243+
bool is_active;
244+
Type table_type;
242245
};
243246

244247
struct LocalDecl {

src/c-writer.cc

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,8 +1510,18 @@ void CWriter::WriteElemInitializers() {
15101510
continue;
15111511
}
15121512

1513-
Write("static const wasm_elem_segment_expr_t elem_segment_exprs_",
1514-
GlobalName(elem_segment->name), "[] = ", OpenBrace());
1513+
switch (elem_segment->elem_type) {
1514+
case Type::FuncRef:
1515+
Write("static const wasm_elem_segment_expr_t elem_segment_exprs_",
1516+
GlobalName(elem_segment->name), "[] = ", OpenBrace());
1517+
break;
1518+
case Type::ExternRef:
1519+
Write("static const wasm_rt_externref_t elem_segment_exprs_",
1520+
GlobalName(elem_segment->name), "[] = ", OpenBrace());
1521+
break;
1522+
default:
1523+
WABT_UNREACHABLE;
1524+
}
15151525

15161526
for (const ExprList& elem_expr : elem_segment->elem_exprs) {
15171527
assert(elem_expr.size() == 1);
@@ -1531,10 +1541,14 @@ void CWriter::WriteElemInitializers() {
15311541
} else {
15321542
Write("0");
15331543
}
1534-
Write("}, ", Newline());
1544+
Write("},", Newline());
15351545
} break;
15361546
case ExprType::RefNull:
1537-
Write("{0, NULL, 0},", Newline());
1547+
if (elem_segment->elem_type == Type::FuncRef) {
1548+
Write("{0, NULL, 0},", Newline());
1549+
} else {
1550+
Write("NULL,", Newline());
1551+
}
15381552
break;
15391553
default:
15401554
WABT_UNREACHABLE;
@@ -1565,28 +1579,32 @@ void CWriter::WriteElemInitializers() {
15651579

15661580
const Table* table = module_->GetTable(elem_segment->table_var);
15671581

1568-
// TODO: Resolve whether nonempty externref-type element segments
1569-
// are permitted (WebAssembly/spec#1543)
1570-
if (table->elem_type != Type::FuncRef) {
1582+
if (table->elem_type != Type::FuncRef &&
1583+
table->elem_type != Type::ExternRef) {
15711584
WABT_UNREACHABLE;
15721585
}
15731586

1574-
Write("funcref_table_init(", ExternalInstancePtr(table->name), ", ");
1587+
Write(GetReferenceTypeName(table->elem_type), "_table_init(",
1588+
ExternalInstancePtr(table->name), ", ");
15751589
if (elem_segment->elem_exprs.empty()) {
15761590
Write("NULL, 0, ");
15771591
} else {
15781592
Write("elem_segment_exprs_", GlobalName(elem_segment->name), ", ",
15791593
elem_segment->elem_exprs.size(), ", ");
15801594
}
15811595
WriteInitExpr(elem_segment->offset);
1582-
if (elem_segment->elem_exprs.empty()) {
1583-
// It's mandatory to handle the case of a zero-length elem segment
1584-
// (even in a module with no types). This must trap if the offset
1585-
// is out of bounds.
1586-
Write(", 0, 0, instance, NULL);", Newline());
1596+
if (table->elem_type == Type::ExternRef) {
1597+
Write(", 0, ", elem_segment->elem_exprs.size(), ");", Newline());
15871598
} else {
1588-
Write(", 0, ", elem_segment->elem_exprs.size(),
1589-
", instance, func_types);", Newline());
1599+
if (elem_segment->elem_exprs.empty()) {
1600+
// It's mandatory to handle the case of a zero-length elem segment
1601+
// (even in a module with no types). This must trap if the offset
1602+
// is out of bounds.
1603+
Write(", 0, 0, instance, NULL);", Newline());
1604+
} else {
1605+
Write(", 0, ", elem_segment->elem_exprs.size(),
1606+
", instance, func_types);", Newline());
1607+
}
15901608
}
15911609
}
15921610

src/interp/binary-reader-interp.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,10 +727,9 @@ Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) {
727727
}
728728

729729
Result BinaryReaderInterp::OnElemSegmentElemType(Index index, Type elem_type) {
730-
validator_.OnElemSegmentElemType(elem_type);
731730
ElemDesc& elem = module_.elems.back();
732731
elem.type = elem_type;
733-
return Result::Ok;
732+
return validator_.OnElemSegmentElemType(GetLocation(), elem_type);
734733
}
735734

736735
Result BinaryReaderInterp::OnElemSegmentElemExprCount(Index index,

src/ir.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -651,12 +651,10 @@ void Var::Destroy() {
651651
uint8_t ElemSegment::GetFlags(const Module* module) const {
652652
uint8_t flags = 0;
653653

654-
bool all_ref_func = elem_type == Type::FuncRef;
655-
656654
switch (kind) {
657655
case SegmentKind::Active: {
658656
Index table_index = module->GetTableIndex(table_var);
659-
if (table_index != 0) {
657+
if (elem_type != Type::FuncRef || table_index != 0) {
660658
flags |= SegExplicitIndex;
661659
}
662660
break;
@@ -671,12 +669,13 @@ uint8_t ElemSegment::GetFlags(const Module* module) const {
671669
break;
672670
}
673671

674-
all_ref_func =
675-
all_ref_func &&
672+
bool all_ref_func =
673+
elem_type == Type::FuncRef &&
676674
std::all_of(elem_exprs.begin(), elem_exprs.end(),
677675
[](const ExprList& elem_expr) {
678676
return elem_expr.front().type() == ExprType::RefFunc;
679677
});
678+
680679
if (!all_ref_func) {
681680
flags |= SegUseElemExprs;
682681
}

src/shared-validator.cc

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,27 @@ Result SharedValidator::OnElemSegment(const Location& loc,
253253
Var table_var,
254254
SegmentKind kind) {
255255
Result result = Result::Ok;
256+
TableType table_type;
256257
if (kind == SegmentKind::Active) {
257-
result |= CheckTableIndex(table_var);
258+
result |= CheckTableIndex(table_var, &table_type);
258259
}
259-
elems_.push_back(ElemType{Type::Void}); // Updated in OnElemSegmentElemType.
260+
// Type gets set later in OnElemSegmentElemType.
261+
elems_.push_back(
262+
ElemType{Type::Void, kind == SegmentKind::Active, table_type.element});
260263
return result;
261264
}
262265

263-
void SharedValidator::OnElemSegmentElemType(Type elem_type) {
264-
elems_.back().element = elem_type;
266+
Result SharedValidator::OnElemSegmentElemType(const Location& loc,
267+
Type elem_type) {
268+
Result result = Result::Ok;
269+
auto& elem = elems_.back();
270+
if (elem.is_active) {
271+
// Check that the type of the elem segment matches the table in which
272+
// it is active.
273+
result |= CheckType(loc, elem.table_type, elem_type, "elem segment");
274+
}
275+
elem.element = elem_type;
276+
return result;
265277
}
266278

267279
Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc,
@@ -272,6 +284,8 @@ Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc,
272284
Result SharedValidator::OnElemSegmentElemExpr_RefFunc(const Location& loc,
273285
Var func_var) {
274286
Result result = Result::Ok;
287+
result |=
288+
CheckType(loc, Type::FuncRef, elems_.back().element, "elem expression");
275289
result |= CheckFuncIndex(func_var);
276290
declared_funcs_.insert(func_var.index());
277291
return result;

src/template/wasm2c.declarations.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,23 @@ static inline void funcref_table_init(wasm_rt_funcref_table_t* dest,
494494
}
495495
}
496496

497+
// Currently we only support initializing externref tables with ref.null.
498+
static inline void externref_table_init(wasm_rt_externref_table_t* dest,
499+
const wasm_rt_externref_t* src,
500+
u32 src_size,
501+
u32 dest_addr,
502+
u32 src_addr,
503+
u32 n) {
504+
if (UNLIKELY(src_addr + (uint64_t)n > src_size))
505+
TRAP(OOB);
506+
if (UNLIKELY(dest_addr + (uint64_t)n > dest->size))
507+
TRAP(OOB);
508+
for (u32 i = 0; i < n; i++) {
509+
const wasm_rt_externref_t* src_expr = &src[src_addr + i];
510+
dest->data[dest_addr + i] = *src_expr;
511+
}
512+
}
513+
497514
#define DEFINE_TABLE_COPY(type) \
498515
static inline void type##_table_copy(wasm_rt_##type##_table_t* dest, \
499516
const wasm_rt_##type##_table_t* src, \

src/tools/spectest-interp.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@ CommandRunner::CommandRunner() : store_(s_features) {
12261226
} const print_funcs[] = {
12271227
{"print", interp::FuncType{{}, {}}},
12281228
{"print_i32", interp::FuncType{{ValueType::I32}, {}}},
1229+
{"print_i64", interp::FuncType{{ValueType::I64}, {}}},
12291230
{"print_f32", interp::FuncType{{ValueType::F32}, {}}},
12301231
{"print_f64", interp::FuncType{{ValueType::F64}, {}}},
12311232
{"print_i32_f32", interp::FuncType{{ValueType::I32, ValueType::F32}, {}}},

src/validator.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,8 @@ Result Validator::CheckModule() {
775775
result_ |= validator_.OnElemSegment(field.loc, f->elem_segment.table_var,
776776
f->elem_segment.kind);
777777

778-
validator_.OnElemSegmentElemType(f->elem_segment.elem_type);
778+
result_ |= validator_.OnElemSegmentElemType(field.loc,
779+
f->elem_segment.elem_type);
779780

780781
// Init expr.
781782
if (f->elem_segment.offset.size()) {

test/parse/expr/bad-memory-copy-differing-type.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,4 @@ out/test/parse/expr/bad-memory-copy-differing-type.txt:76:5: error: type mismatc
119119
out/test/parse/expr/bad-memory-copy-differing-type.txt:81:5: error: type mismatch in memory.copy, expected [i32, i32, i32] but got [i32, i32, i64]
120120
memory.copy $mem32 $mem32
121121
^^^^^^^^^^^
122-
;;; STDERR ;;)
122+
;;; STDERR ;;)

test/spec-wasm2c-prefix.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ void Z_spectestZ_print_i32(Z_spectest_instance_t* instance, uint32_t i) {
270270
printf("spectest.print_i32(%d)\n", i);
271271
}
272272

273+
void Z_spectestZ_print_i64(Z_spectest_instance_t* instance, uint64_t i) {
274+
printf("spectest.print_i64(%" PRIu64 ")\n", i);
275+
}
276+
273277
void Z_spectestZ_print_f32(Z_spectest_instance_t* instance, float f) {
274278
printf("spectest.print_f32(%g)\n", f);
275279
}

0 commit comments

Comments
 (0)