diff options
author | Sam Clegg <sbc@chromium.org> | 2022-11-13 10:14:36 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-13 18:14:36 +0000 |
commit | 0ec54cbdd782b894d9872058dad60f1ee6bd6e44 (patch) | |
tree | 28f5d781841995da833cf736a6e685fb1dd7c1f2 /src | |
parent | a3c6ec4364f87f72c58bce85ab0d3bd0289505f0 (diff) | |
download | wabt-0ec54cbdd782b894d9872058dad60f1ee6bd6e44.tar.gz wabt-0ec54cbdd782b894d9872058dad60f1ee6bd6e44.tar.bz2 wabt-0ec54cbdd782b894d9872058dad60f1ee6bd6e44.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/c-writer.cc | 48 | ||||
-rw-r--r-- | src/interp/binary-reader-interp.cc | 3 | ||||
-rw-r--r-- | src/ir.cc | 9 | ||||
-rw-r--r-- | src/shared-validator.cc | 22 | ||||
-rw-r--r-- | src/template/wasm2c.declarations.c | 17 | ||||
-rw-r--r-- | src/tools/spectest-interp.cc | 1 | ||||
-rw-r--r-- | src/validator.cc | 3 |
7 files changed, 76 insertions, 27 deletions
diff --git a/src/c-writer.cc b/src/c-writer.cc index 517cc80e..ed255d00 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1510,8 +1510,18 @@ void CWriter::WriteElemInitializers() { continue; } - Write("static const wasm_elem_segment_expr_t elem_segment_exprs_", - GlobalName(elem_segment->name), "[] = ", OpenBrace()); + switch (elem_segment->elem_type) { + case Type::FuncRef: + Write("static const wasm_elem_segment_expr_t elem_segment_exprs_", + GlobalName(elem_segment->name), "[] = ", OpenBrace()); + break; + case Type::ExternRef: + Write("static const wasm_rt_externref_t elem_segment_exprs_", + GlobalName(elem_segment->name), "[] = ", OpenBrace()); + break; + default: + WABT_UNREACHABLE; + } for (const ExprList& elem_expr : elem_segment->elem_exprs) { assert(elem_expr.size() == 1); @@ -1531,10 +1541,14 @@ void CWriter::WriteElemInitializers() { } else { Write("0"); } - Write("}, ", Newline()); + Write("},", Newline()); } break; case ExprType::RefNull: - Write("{0, NULL, 0},", Newline()); + if (elem_segment->elem_type == Type::FuncRef) { + Write("{0, NULL, 0},", Newline()); + } else { + Write("NULL,", Newline()); + } break; default: WABT_UNREACHABLE; @@ -1565,13 +1579,13 @@ void CWriter::WriteElemInitializers() { const Table* table = module_->GetTable(elem_segment->table_var); - // TODO: Resolve whether nonempty externref-type element segments - // are permitted (WebAssembly/spec#1543) - if (table->elem_type != Type::FuncRef) { + if (table->elem_type != Type::FuncRef && + table->elem_type != Type::ExternRef) { WABT_UNREACHABLE; } - Write("funcref_table_init(", ExternalInstancePtr(table->name), ", "); + Write(GetReferenceTypeName(table->elem_type), "_table_init(", + ExternalInstancePtr(table->name), ", "); if (elem_segment->elem_exprs.empty()) { Write("NULL, 0, "); } else { @@ -1579,14 +1593,18 @@ void CWriter::WriteElemInitializers() { elem_segment->elem_exprs.size(), ", "); } WriteInitExpr(elem_segment->offset); - if (elem_segment->elem_exprs.empty()) { - // It's mandatory to handle the case of a zero-length elem segment - // (even in a module with no types). This must trap if the offset - // is out of bounds. - Write(", 0, 0, instance, NULL);", Newline()); + if (table->elem_type == Type::ExternRef) { + Write(", 0, ", elem_segment->elem_exprs.size(), ");", Newline()); } else { - Write(", 0, ", elem_segment->elem_exprs.size(), - ", instance, func_types);", Newline()); + if (elem_segment->elem_exprs.empty()) { + // It's mandatory to handle the case of a zero-length elem segment + // (even in a module with no types). This must trap if the offset + // is out of bounds. + Write(", 0, 0, instance, NULL);", Newline()); + } else { + Write(", 0, ", elem_segment->elem_exprs.size(), + ", instance, func_types);", Newline()); + } } } diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc index def91b64..42f4c013 100644 --- a/src/interp/binary-reader-interp.cc +++ b/src/interp/binary-reader-interp.cc @@ -727,10 +727,9 @@ Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) { } Result BinaryReaderInterp::OnElemSegmentElemType(Index index, Type elem_type) { - validator_.OnElemSegmentElemType(elem_type); ElemDesc& elem = module_.elems.back(); elem.type = elem_type; - return Result::Ok; + return validator_.OnElemSegmentElemType(GetLocation(), elem_type); } Result BinaryReaderInterp::OnElemSegmentElemExprCount(Index index, @@ -651,12 +651,10 @@ void Var::Destroy() { uint8_t ElemSegment::GetFlags(const Module* module) const { uint8_t flags = 0; - bool all_ref_func = elem_type == Type::FuncRef; - switch (kind) { case SegmentKind::Active: { Index table_index = module->GetTableIndex(table_var); - if (table_index != 0) { + if (elem_type != Type::FuncRef || table_index != 0) { flags |= SegExplicitIndex; } break; @@ -671,12 +669,13 @@ uint8_t ElemSegment::GetFlags(const Module* module) const { break; } - all_ref_func = - all_ref_func && + bool all_ref_func = + elem_type == Type::FuncRef && std::all_of(elem_exprs.begin(), elem_exprs.end(), [](const ExprList& elem_expr) { return elem_expr.front().type() == ExprType::RefFunc; }); + if (!all_ref_func) { flags |= SegUseElemExprs; } diff --git a/src/shared-validator.cc b/src/shared-validator.cc index efbd02f8..ec596cad 100644 --- a/src/shared-validator.cc +++ b/src/shared-validator.cc @@ -253,15 +253,27 @@ Result SharedValidator::OnElemSegment(const Location& loc, Var table_var, SegmentKind kind) { Result result = Result::Ok; + TableType table_type; if (kind == SegmentKind::Active) { - result |= CheckTableIndex(table_var); + result |= CheckTableIndex(table_var, &table_type); } - elems_.push_back(ElemType{Type::Void}); // Updated in OnElemSegmentElemType. + // Type gets set later in OnElemSegmentElemType. + elems_.push_back( + ElemType{Type::Void, kind == SegmentKind::Active, table_type.element}); return result; } -void SharedValidator::OnElemSegmentElemType(Type elem_type) { - elems_.back().element = elem_type; +Result SharedValidator::OnElemSegmentElemType(const Location& loc, + Type elem_type) { + Result result = Result::Ok; + auto& elem = elems_.back(); + if (elem.is_active) { + // Check that the type of the elem segment matches the table in which + // it is active. + result |= CheckType(loc, elem.table_type, elem_type, "elem segment"); + } + elem.element = elem_type; + return result; } Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc, @@ -272,6 +284,8 @@ Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc, Result SharedValidator::OnElemSegmentElemExpr_RefFunc(const Location& loc, Var func_var) { Result result = Result::Ok; + result |= + CheckType(loc, Type::FuncRef, elems_.back().element, "elem expression"); result |= CheckFuncIndex(func_var); declared_funcs_.insert(func_var.index()); return result; diff --git a/src/template/wasm2c.declarations.c b/src/template/wasm2c.declarations.c index 7d9d64ad..c262b277 100644 --- a/src/template/wasm2c.declarations.c +++ b/src/template/wasm2c.declarations.c @@ -494,6 +494,23 @@ static inline void funcref_table_init(wasm_rt_funcref_table_t* dest, } } +// Currently we only support initializing externref tables with ref.null. +static inline void externref_table_init(wasm_rt_externref_table_t* dest, + const wasm_rt_externref_t* src, + u32 src_size, + u32 dest_addr, + u32 src_addr, + u32 n) { + if (UNLIKELY(src_addr + (uint64_t)n > src_size)) + TRAP(OOB); + if (UNLIKELY(dest_addr + (uint64_t)n > dest->size)) + TRAP(OOB); + for (u32 i = 0; i < n; i++) { + const wasm_rt_externref_t* src_expr = &src[src_addr + i]; + dest->data[dest_addr + i] = *src_expr; + } +} + #define DEFINE_TABLE_COPY(type) \ static inline void type##_table_copy(wasm_rt_##type##_table_t* dest, \ const wasm_rt_##type##_table_t* src, \ diff --git a/src/tools/spectest-interp.cc b/src/tools/spectest-interp.cc index aae11347..5df00894 100644 --- a/src/tools/spectest-interp.cc +++ b/src/tools/spectest-interp.cc @@ -1226,6 +1226,7 @@ CommandRunner::CommandRunner() : store_(s_features) { } const print_funcs[] = { {"print", interp::FuncType{{}, {}}}, {"print_i32", interp::FuncType{{ValueType::I32}, {}}}, + {"print_i64", interp::FuncType{{ValueType::I64}, {}}}, {"print_f32", interp::FuncType{{ValueType::F32}, {}}}, {"print_f64", interp::FuncType{{ValueType::F64}, {}}}, {"print_i32_f32", interp::FuncType{{ValueType::I32, ValueType::F32}, {}}}, diff --git a/src/validator.cc b/src/validator.cc index f05018ab..c1ef6422 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -775,7 +775,8 @@ Result Validator::CheckModule() { result_ |= validator_.OnElemSegment(field.loc, f->elem_segment.table_var, f->elem_segment.kind); - validator_.OnElemSegmentElemType(f->elem_segment.elem_type); + result_ |= validator_.OnElemSegmentElemType(field.loc, + f->elem_segment.elem_type); // Init expr. if (f->elem_segment.offset.size()) { |