Skip to content

Commit 1917fb3

Browse files
author
Zoltan Herczeg
committed
Support all gc tests
1 parent 1a8e2ac commit 1917fb3

37 files changed

+2367
-23
lines changed

include/wabt/interp/interp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,7 @@ class Thread {
12371237
void Push(Ref);
12381238

12391239
bool CheckRefCast(Ref ref, Type expected);
1240+
bool CheckRefFunc(Ref ref, Index expected_index, Func* new_func);
12401241

12411242
template <typename R, typename T>
12421243
using UnopFunc = R WABT_VECTORCALL(T);

include/wabt/shared-validator.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ class SharedValidator {
9292
Result OnTable(const Location&, Type elem_type, const Limits&, bool, bool);
9393
Result OnMemory(const Location&, const Limits&, uint32_t page_size);
9494
Result OnGlobalImport(const Location&, Type type, bool mutable_);
95-
Result OnGlobal(const Location&, Type type, bool mutable_);
95+
Result BeginGlobal(const Location&, Type type, bool mutable_);
96+
Result EndGlobal(const Location&);
9697
Result OnTag(const Location&, Var sig_var);
9798

9899
Result OnExport(const Location&,
@@ -383,7 +384,7 @@ class SharedValidator {
383384
std::vector<TagType> tags_; // Includes imported and defined.
384385
std::vector<ElemType> elems_;
385386
Index starts_ = 0;
386-
Index num_imported_globals_ = 0;
387+
Index last_initialized_global_ = 0;
387388
Index data_segments_ = 0;
388389
Index last_rec_type_end_ = 0;
389390
// Recursive type checks may enter to infinite loop for invalid values.

src/binary-writer-spec.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ void BinaryWriterSpec::WriteVar(const Var& var) {
161161
void BinaryWriterSpec::WriteTypeObject(Type type) {
162162
json_stream_->Writef("{");
163163
WriteKey("type");
164+
if (type.IsReferenceWithIndex()) {
165+
// This should happen only for invalid modules.
166+
type = Type::AnyRef;
167+
}
164168
WriteString(type.GetName().c_str());
165169
json_stream_->Writef("}");
166170
}
@@ -284,6 +288,7 @@ void BinaryWriterSpec::WriteConst(const Const& const_) {
284288
break;
285289
}
286290

291+
case Type::NullFuncRef:
287292
case Type::FuncRef: {
288293
WriteString("funcref");
289294
WriteSeparator();

src/interp/binary-reader-interp.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ Result BinaryReaderInterp::OnGlobalCount(Index count) {
805805
}
806806

807807
Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
808-
CHECK_RESULT(validator_.OnGlobal(GetLocation(), type, mutable_));
808+
CHECK_RESULT(validator_.BeginGlobal(GetLocation(), type, mutable_));
809809
GlobalType global_type{type, ToMutability(mutable_)};
810810
FuncDesc init_func{FuncType{{}, {type}}, {}, Istream::kInvalidOffset, {}};
811811
module_.globals.push_back(GlobalDesc{global_type, init_func});
@@ -838,6 +838,7 @@ Result BinaryReaderInterp::BeginInitExpr(FuncDesc* func) {
838838
}
839839

840840
Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
841+
CHECK_RESULT(validator_.EndGlobal(GetLocation()));
841842
return EndInitExpr();
842843
}
843844

@@ -1464,7 +1465,8 @@ Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index,
14641465
CHECK_RESULT(validator_.OnCallIndirect(GetLocation(),
14651466
Var(sig_index, GetLocation()),
14661467
Var(table_index, GetLocation())));
1467-
istream_.Emit(Opcode::CallIndirect, table_index, sig_index);
1468+
istream_.Emit(Opcode::CallIndirect, table_index,
1469+
module_.func_types[sig_index].canonical_index);
14681470
return Result::Ok;
14691471
}
14701472

@@ -1529,7 +1531,8 @@ Result BinaryReaderInterp::OnReturnCallIndirectExpr(Index sig_index,
15291531
Var(table_index, GetLocation())));
15301532
istream_.EmitDropKeep(drop_count, keep_count);
15311533
istream_.EmitCatchDrop(catch_drop_count);
1532-
istream_.Emit(Opcode::ReturnCallIndirect, table_index, sig_index);
1534+
istream_.Emit(Opcode::ReturnCallIndirect, table_index,
1535+
module_.func_types[sig_index].canonical_index);
15331536
return Result::Ok;
15341537
}
15351538

src/interp/interp.cc

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,31 @@ bool Thread::CheckRefCast(Ref ref, Type expected) {
15981598
return false;
15991599
}
16001600

1601+
bool Thread::CheckRefFunc(Ref ref, Index expected_type_index, Func* new_func) {
1602+
// Validator checks that the table contains funcrefs.
1603+
assert(!ref.IsI31OrHostVal());
1604+
Object* object = store_.UnsafeGet<Object>(ref).get();
1605+
assert(Func::classof(object));
1606+
1607+
const FuncType& type = cast<Func>(object)->type();
1608+
if (type.func_types != &mod_->desc().func_types) {
1609+
auto&& func_type = mod_->desc().func_types[expected_type_index];
1610+
return Succeeded(Match(new_func->type(), func_type, nullptr));
1611+
}
1612+
Index actual_type_index = type.canonical_index;
1613+
1614+
do {
1615+
if (expected_type_index == actual_type_index) {
1616+
return true;
1617+
}
1618+
1619+
actual_type_index =
1620+
mod_->desc().func_types[actual_type_index].canonical_sub_index;
1621+
} while (actual_type_index != kInvalidIndex);
1622+
1623+
return false;
1624+
}
1625+
16011626
RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
16021627
using O = Opcode;
16031628

@@ -1668,15 +1693,14 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
16681693
case O::CallIndirect:
16691694
case O::ReturnCallIndirect: {
16701695
Table::Ptr table{store_, inst_->tables()[instr.imm_u32x2.fst]};
1671-
auto&& func_type = mod_->desc().func_types[instr.imm_u32x2.snd];
16721696
u64 entry = PopPtr(table);
16731697
TRAP_IF(entry >= table->elements().size(), "undefined table index");
16741698
auto new_func_ref = table->elements()[entry];
16751699
TRAP_IF(new_func_ref == Ref::Null, "uninitialized table element");
16761700
Func::Ptr new_func{store_, new_func_ref};
1677-
TRAP_IF(
1678-
Failed(Match(new_func->type(), func_type, nullptr)),
1679-
"indirect call signature mismatch"); // TODO: don't use "signature"
1701+
// TODO: don't use "signature"
1702+
TRAP_IF(!CheckRefFunc(new_func_ref, instr.imm_u32x2.snd, new_func.get()),
1703+
"indirect call signature mismatch");
16801704
if (instr.op == O::ReturnCallIndirect) {
16811705
return DoReturnCall(new_func, out_trap);
16821706
} else {

src/shared-validator.cc

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ Result SharedValidator::OnFuncType(const Location& loc,
8585
}
8686

8787
type_validation_result_ |= result;
88-
result |= CheckGCTypeExtension(loc, gc_ext);
8988
}
89+
result |= CheckGCTypeExtension(loc, gc_ext);
9090

9191
return result;
9292
}
@@ -229,19 +229,26 @@ Result SharedValidator::OnGlobalImport(const Location& loc,
229229
result |= PrintError(loc, "mutable globals cannot be imported");
230230
}
231231
globals_.push_back(GlobalType{type, mutable_});
232-
++num_imported_globals_;
232+
++last_initialized_global_;
233233
return result;
234234
}
235235

236-
Result SharedValidator::OnGlobal(const Location& loc,
237-
Type type,
238-
bool mutable_) {
236+
Result SharedValidator::BeginGlobal(const Location& loc,
237+
Type type,
238+
bool mutable_) {
239239
CHECK_RESULT(
240240
CheckReferenceType(loc, type, type_fields_.NumTypes(), "globals"));
241241
globals_.push_back(GlobalType{type, mutable_});
242242
return Result::Ok;
243243
}
244244

245+
Result SharedValidator::EndGlobal(const Location&) {
246+
if (options_.features.gc_enabled()) {
247+
last_initialized_global_++;
248+
}
249+
return Result::Ok;
250+
}
251+
245252
Result SharedValidator::CheckType(const Location& loc,
246253
Type actual,
247254
Type expected,
@@ -268,8 +275,6 @@ Result SharedValidator::CheckReferenceType(const Location& loc,
268275

269276
Result SharedValidator::CheckGCTypeExtension(const Location& loc,
270277
GCTypeExtension* gc_ext) {
271-
assert(options_.features.function_references_enabled());
272-
273278
TypeEntry& entry = type_fields_.type_entries.back();
274279
Index current_index = type_fields_.NumTypes() - 1;
275280
Index end_index;
@@ -778,8 +783,7 @@ Index SharedValidator::GetCanonicalTypeIndex(Index type_index) {
778783
return kInvalidIndex;
779784
}
780785

781-
if (options_.features.function_references_enabled() &&
782-
Succeeded(type_validation_result_)) {
786+
if (Succeeded(type_validation_result_)) {
783787
return type_fields_.type_entries[type_index].canonical_index;
784788
}
785789

@@ -1190,7 +1194,7 @@ Result SharedValidator::OnCallIndirect(const Location& loc,
11901194
TableType table_type;
11911195
result |= CheckFuncTypeIndex(sig_var, &func_type);
11921196
result |= CheckTableIndex(table_var, &table_type);
1193-
if (table_type.element != Type::FuncRef) {
1197+
if (Failed(typechecker_.CheckType(table_type.element, Type::FuncRef))) {
11941198
result |= PrintError(
11951199
loc,
11961200
"type mismatch: call_indirect must reference table of funcref type");
@@ -1299,7 +1303,7 @@ Result SharedValidator::OnGlobalGet(const Location& loc, Var global_var) {
12991303
result |= CheckGlobalIndex(global_var, &global_type);
13001304
result |= typechecker_.OnGlobalGet(global_type.type);
13011305
if (Succeeded(result) && in_init_expr_) {
1302-
if (global_var.index() >= num_imported_globals_) {
1306+
if (global_var.index() >= last_initialized_global_) {
13031307
result |= PrintError(
13041308
global_var.loc,
13051309
"initializer expression can only reference an imported global");

src/tools/spectest-interp.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,8 @@ wabt::Result CommandRunner::CheckAssertReturnResult(
20032003
ok = obj->kind() == ObjectKind::Array ||
20042004
obj->kind() == ObjectKind::Struct;
20052005
}
2006+
} else {
2007+
ok = expected.value.type == Type::AnyRef;
20062008
}
20072009
break;
20082010
}

src/validator.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,14 +1068,15 @@ Result Validator::CheckModule() {
10681068
for (const ModuleField& field : module->fields) {
10691069
if (auto* f = dyn_cast<GlobalModuleField>(&field)) {
10701070
result_ |=
1071-
validator_.OnGlobal(field.loc, f->global.type, f->global.mutable_);
1071+
validator_.BeginGlobal(field.loc, f->global.type, f->global.mutable_);
10721072

10731073
// Init expr.
10741074
result_ |= validator_.BeginInitExpr(field.loc, f->global.type);
10751075
ExprVisitor visitor(this);
10761076
result_ |=
10771077
visitor.VisitExprList(const_cast<ExprList&>(f->global.init_expr));
10781078
result_ |= validator_.EndInitExpr();
1079+
result_ |= validator_.EndGlobal(field.loc);
10791080
}
10801081
}
10811082

test/spec/call_indirect.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ out/test/spec/call_indirect.wast:776: assert_malformed passed:
8686
^^^^^^^^^^^^^
8787
out/test/spec/call_indirect.wast:791: assert_invalid passed:
8888
out/test/spec/call_indirect/call_indirect.13.wasm:000001c: error: table variable out of range: 0 (max 0)
89-
out/test/spec/call_indirect/call_indirect.13.wasm:000001c: error: type mismatch: call_indirect must reference table of funcref type
9089
000001c: error: OnCallIndirectExpr callback failed
9190
out/test/spec/call_indirect.wast:799: assert_invalid passed:
9291
out/test/spec/call_indirect/call_indirect.14.wasm:0000023: error: type mismatch in i32.eqz, expected [i32] but got []

test/spec/gc/array_new_data.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
;;; TOOL: run-interp-spec
2+
;;; STDIN_FILE: third_party/testsuite/proposals/gc/array_new_data.wast
3+
;;; ARGS*: --enable-gc
4+
(;; STDOUT ;;;
5+
out/test/spec/gc/array_new_data.wast:18: assert_trap passed: invalid range
6+
out/test/spec/gc/array_new_data.wast:19: assert_trap passed: invalid range
7+
out/test/spec/gc/array_new_data.wast:20: assert_trap passed: invalid range
8+
out/test/spec/gc/array_new_data.wast:21: assert_trap passed: invalid range
9+
15/15 tests passed.
10+
;;; STDOUT ;;)

0 commit comments

Comments
 (0)