Skip to content

Commit 89a2eae

Browse files
committed
Support all gc tests
1 parent 3bb15c6 commit 89a2eae

37 files changed

Lines changed: 2366 additions & 22 deletions

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
@@ -99,7 +99,8 @@ class SharedValidator {
9999
Result OnTable(const Location&, Type elem_type, const Limits&, TableImportStatus import_status, TableInitExprStatus init_provided);
100100
Result OnMemory(const Location&, const Limits&, uint32_t page_size);
101101
Result OnGlobalImport(const Location&, Type type, bool mutable_);
102-
Result OnGlobal(const Location&, Type type, bool mutable_);
102+
Result BeginGlobal(const Location&, Type type, bool mutable_);
103+
Result EndGlobal(const Location&);
103104
Result OnTag(const Location&, Var sig_var);
104105

105106
Result OnExport(const Location&,
@@ -394,7 +395,7 @@ class SharedValidator {
394395
std::vector<TagType> tags_; // Includes imported and defined.
395396
std::vector<ElemType> elems_;
396397
Index starts_ = 0;
397-
Index num_imported_globals_ = 0;
398+
Index last_initialized_global_ = 0;
398399
Index data_segments_ = 0;
399400
Index last_rec_type_end_ = 0;
400401
// 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
@@ -812,7 +812,7 @@ Result BinaryReaderInterp::OnGlobalCount(Index count) {
812812
}
813813

814814
Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
815-
CHECK_RESULT(validator_.OnGlobal(GetLocation(), type, mutable_));
815+
CHECK_RESULT(validator_.BeginGlobal(GetLocation(), type, mutable_));
816816
GlobalType global_type{type, ToMutability(mutable_)};
817817
FuncDesc init_func{FuncType{{}, {type}}, {}, Istream::kInvalidOffset, {}};
818818
module_.globals.push_back(GlobalDesc{global_type, init_func});
@@ -845,6 +845,7 @@ Result BinaryReaderInterp::BeginInitExpr(FuncDesc* func) {
845845
}
846846

847847
Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
848+
CHECK_RESULT(validator_.EndGlobal(GetLocation()));
848849
return EndInitExpr();
849850
}
850851

@@ -1466,7 +1467,8 @@ Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index,
14661467
CHECK_RESULT(validator_.OnCallIndirect(GetLocation(),
14671468
Var(sig_index, GetLocation()),
14681469
Var(table_index, GetLocation())));
1469-
istream_.Emit(Opcode::CallIndirect, table_index, sig_index);
1470+
istream_.Emit(Opcode::CallIndirect, table_index,
1471+
module_.func_types[sig_index].canonical_index);
14701472
return Result::Ok;
14711473
}
14721474

@@ -1531,7 +1533,8 @@ Result BinaryReaderInterp::OnReturnCallIndirectExpr(Index sig_index,
15311533
Var(table_index, GetLocation())));
15321534
istream_.EmitDropKeep(drop_count, keep_count);
15331535
istream_.EmitCatchDrop(catch_drop_count);
1534-
istream_.Emit(Opcode::ReturnCallIndirect, table_index, sig_index);
1536+
istream_.Emit(Opcode::ReturnCallIndirect, table_index,
1537+
module_.func_types[sig_index].canonical_index);
15351538
return Result::Ok;
15361539
}
15371540

src/interp/interp.cc

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

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

@@ -1676,15 +1701,14 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
16761701
case O::CallIndirect:
16771702
case O::ReturnCallIndirect: {
16781703
Table::Ptr table{store_, inst_->tables()[instr.imm_u32x2.fst]};
1679-
auto&& func_type = mod_->desc().func_types[instr.imm_u32x2.snd];
16801704
u64 entry = PopPtr(table);
16811705
TRAP_IF(entry >= table->elements().size(), "undefined table index");
16821706
auto new_func_ref = table->elements()[entry];
16831707
TRAP_IF(new_func_ref == Ref::Null, "uninitialized table element");
16841708
Func::Ptr new_func{store_, new_func_ref};
1685-
TRAP_IF(
1686-
Failed(Match(new_func->type(), func_type, nullptr)),
1687-
"indirect call signature mismatch"); // TODO: don't use "signature"
1709+
// TODO: don't use "signature"
1710+
TRAP_IF(!CheckRefFunc(new_func_ref, instr.imm_u32x2.snd, new_func.get()),
1711+
"indirect call signature mismatch");
16881712
if (instr.op == O::ReturnCallIndirect) {
16891713
return DoReturnCall(new_func, out_trap);
16901714
} else {

src/shared-validator.cc

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ Result SharedValidator::OnFuncType(const Location& loc,
8888
}
8989

9090
type_validation_result_ |= result;
91-
result |= CheckSupertypes(loc, supertypes);
9291
}
92+
result |= CheckSupertypes(loc, supertypes);
9393

9494
return result;
9595
}
@@ -237,19 +237,26 @@ Result SharedValidator::OnGlobalImport(const Location& loc,
237237
result |= PrintError(loc, "mutable globals cannot be imported");
238238
}
239239
globals_.push_back(GlobalType{type, mutable_});
240-
++num_imported_globals_;
240+
++last_initialized_global_;
241241
return result;
242242
}
243243

244-
Result SharedValidator::OnGlobal(const Location& loc,
245-
Type type,
246-
bool mutable_) {
244+
Result SharedValidator::BeginGlobal(const Location& loc,
245+
Type type,
246+
bool mutable_) {
247247
CHECK_RESULT(
248248
CheckReferenceType(loc, type, type_fields_.NumTypes(), "globals"));
249249
globals_.push_back(GlobalType{type, mutable_});
250250
return Result::Ok;
251251
}
252252

253+
Result SharedValidator::EndGlobal(const Location&) {
254+
if (options_.features.gc_enabled()) {
255+
last_initialized_global_++;
256+
}
257+
return Result::Ok;
258+
}
259+
253260
Result SharedValidator::CheckType(const Location& loc,
254261
Type actual,
255262
Type expected,
@@ -278,8 +285,6 @@ Result SharedValidator::CheckReferenceType(const Location& loc,
278285

279286
Result SharedValidator::CheckSupertypes(const Location& loc,
280287
SupertypesInfo* supertypes) {
281-
assert(options_.features.function_references_enabled());
282-
283288
TypeEntry& entry = type_fields_.type_entries.back();
284289
Index current_index = type_fields_.NumTypes() - 1;
285290
Index end_index;
@@ -787,8 +792,7 @@ Index SharedValidator::GetCanonicalTypeIndex(Index type_index) {
787792
return kInvalidIndex;
788793
}
789794

790-
if (options_.features.function_references_enabled() &&
791-
Succeeded(type_validation_result_)) {
795+
if (Succeeded(type_validation_result_)) {
792796
return type_fields_.type_entries[type_index].canonical_index;
793797
}
794798

@@ -1321,7 +1325,7 @@ Result SharedValidator::OnGlobalGet(const Location& loc, Var global_var) {
13211325
result |= CheckGlobalIndex(global_var, &global_type);
13221326
result |= typechecker_.OnGlobalGet(global_type.type);
13231327
if (Succeeded(result) && in_init_expr_) {
1324-
if (global_var.index() >= num_imported_globals_) {
1328+
if (global_var.index() >= last_initialized_global_) {
13251329
result |= PrintError(
13261330
global_var.loc,
13271331
"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
@@ -2001,6 +2001,8 @@ wabt::Result CommandRunner::CheckAssertReturnResult(
20012001
ok = obj->kind() == ObjectKind::Array ||
20022002
obj->kind() == ObjectKind::Struct;
20032003
}
2004+
} else {
2005+
ok = expected.value.type == Type::AnyRef;
20042006
}
20052007
break;
20062008
}

src/validator.cc

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

10851085
// Init expr.
10861086
result_ |= validator_.BeginInitExpr(field.loc, f->global.type);
10871087
ExprVisitor visitor(this);
10881088
result_ |=
10891089
visitor.VisitExprList(const_cast<ExprList&>(f->global.init_expr));
10901090
result_ |= validator_.EndInitExpr();
1091+
result_ |= validator_.EndGlobal(field.loc);
10911092
}
10921093
}
10931094

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)