Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions scripts/fuzz_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ def is_git_repo():
'exception-handling.wast',
'translate-to-new-eh.wast',
'rse-eh.wast',
# Shared types implementation in progress
'type-merging-shared.wast',
'shared-types.wast',
'shared-struct.wast',
]


Expand Down
12 changes: 5 additions & 7 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
void addArrayType(ArrayT) {}
void setOpen() {}
void setShared() {}
Result<> addSubtype(Index) { return Ok{}; }
Result<> addSubtype(HeapTypeT) { return Ok{}; }
void finishSubtype(Name name, Index pos) {
// TODO: type annotations
subtypeDefs.push_back({name, pos, Index(subtypeDefs.size()), {}});
Expand Down Expand Up @@ -1080,11 +1080,8 @@ struct ParseTypeDefsCtx : TypeParserCtx<ParseTypeDefsCtx> {

void setShared() { builder[index].setShared(); }

Result<> addSubtype(Index super) {
if (super >= builder.size()) {
return in.err("supertype index out of bounds");
}
builder[index].subTypeOf(builder[super]);
Result<> addSubtype(HeapTypeT super) {
builder[index].subTypeOf(super);
return Ok{};
}

Expand Down Expand Up @@ -1121,7 +1118,8 @@ struct ParseImplicitTypeDefsCtx : TypeParserCtx<ParseImplicitTypeDefsCtx> {
: TypeParserCtx<ParseImplicitTypeDefsCtx>(typeIndices), in(in),
types(types), implicitTypes(implicitTypes) {
for (auto type : types) {
if (type.isSignature() && type.getRecGroup().size() == 1) {
if (type.isSignature() && type.getRecGroup().size() == 1 &&
!type.isShared()) {
sigTypes.insert({type.getSignature(), type});
}
}
Expand Down
16 changes: 9 additions & 7 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ Result<> ignore(Ctx&, Index, const std::vector<Annotation>&) {
}

// Modules
template<typename Ctx> MaybeResult<Index> maybeTypeidx(Ctx& ctx);
template<typename Ctx>
MaybeResult<typename Ctx::HeapTypeT> maybeTypeidx(Ctx& ctx);
template<typename Ctx> Result<typename Ctx::HeapTypeT> typeidx(Ctx&);
template<typename Ctx>
Result<typename Ctx::FieldIdxT> fieldidx(Ctx&, typename Ctx::HeapTypeT);
Expand Down Expand Up @@ -2436,23 +2437,24 @@ makeSuspend(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) {

// typeidx ::= x:u32 => x
// | v:id => x (if types[x] = v)
template<typename Ctx> MaybeResult<Index> maybeTypeidx(Ctx& ctx) {
template<typename Ctx>
MaybeResult<typename Ctx::HeapTypeT> maybeTypeidx(Ctx& ctx) {
if (auto x = ctx.in.takeU32()) {
return *x;
return ctx.getHeapTypeFromIdx(*x);
}
if (auto id = ctx.in.takeID()) {
// TODO: Fix position to point to start of id, not next element.
auto idx = ctx.getTypeIndex(*id);
CHECK_ERR(idx);
return *idx;
return ctx.getHeapTypeFromIdx(*idx);
}
return {};
}

template<typename Ctx> Result<typename Ctx::HeapTypeT> typeidx(Ctx& ctx) {
if (auto idx = maybeTypeidx(ctx)) {
CHECK_ERR(idx);
return ctx.getHeapTypeFromIdx(*idx);
if (auto t = maybeTypeidx(ctx)) {
CHECK_ERR(t);
return *t;
}
return ctx.in.err("expected type index or identifier");
}
Expand Down
1 change: 1 addition & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ enum EncodedType {
Array = -0x22, // 0x5e
Sub = -0x30, // 0x50
SubFinal = -0x31, // 0x4f
Shared = -0x24, // 0x65
// isorecursive recursion groups
Rec = -0x32, // 0x4e
// block_type
Expand Down
20 changes: 20 additions & 0 deletions src/wasm-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,26 @@ class HeapType {

inline bool Type::isNull() const { return isRef() && getHeapType().isBottom(); }

namespace HeapTypes {

constexpr HeapType ext = HeapType::ext;
constexpr HeapType func = HeapType::func;
constexpr HeapType cont = HeapType::cont;
constexpr HeapType any = HeapType::any;
constexpr HeapType eq = HeapType::eq;
constexpr HeapType i31 = HeapType::i31;
constexpr HeapType struct_ = HeapType::struct_;
constexpr HeapType array = HeapType::array;
constexpr HeapType exn = HeapType::exn;
constexpr HeapType string = HeapType::string;
constexpr HeapType none = HeapType::none;
constexpr HeapType noext = HeapType::noext;
constexpr HeapType nofunc = HeapType::nofunc;
constexpr HeapType nocont = HeapType::nocont;
constexpr HeapType noexn = HeapType::noexn;

} // namespace HeapTypes

// A recursion group consisting of one or more HeapTypes. HeapTypes with single
// members are encoded without using any additional memory, which is why
// `getHeapTypes` has to return a vector by value; it might have to create one
Expand Down
7 changes: 7 additions & 0 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ void WasmBinaryWriter::writeTypes() {
o << U32LEB(0);
}
}
if (type.isShared()) {
o << S32LEB(BinaryConsts::EncodedType::Shared);
}
if (type.isSignature()) {
o << S32LEB(BinaryConsts::EncodedType::Func);
auto sig = type.getSignature();
Expand Down Expand Up @@ -2391,6 +2394,10 @@ void WasmBinaryReader::readTypes() {
}
form = getS32LEB();
}
if (form == BinaryConsts::Shared) {
builder[i].setShared();
form = getS32LEB();
}
if (form == BinaryConsts::EncodedType::Func) {
builder[i] = readSignatureDef();
} else if (form == BinaryConsts::EncodedType::Cont) {
Expand Down
8 changes: 4 additions & 4 deletions test/example/typeinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,16 @@ void test_compound() {
void test_printing() {
{
std::cout << ";; Heap types\n";
std::cout << HeapType(HeapType::func) << "\n";
std::cout << HeapTypes::func << "\n";
std::cout << Type(HeapType::func, Nullable) << "\n";
std::cout << Type(HeapType::func, NonNullable) << "\n";
std::cout << HeapType(HeapType::any) << "\n";
std::cout << HeapTypes::any << "\n";
std::cout << Type(HeapType::any, Nullable) << "\n";
std::cout << Type(HeapType::any, NonNullable) << "\n";
std::cout << HeapType(HeapType::eq) << "\n";
std::cout << HeapTypes::eq << "\n";
std::cout << Type(HeapType::eq, Nullable) << "\n";
std::cout << Type(HeapType::eq, NonNullable) << "\n";
std::cout << HeapType(HeapType::i31) << "\n";
std::cout << HeapTypes::i31 << "\n";
std::cout << Type(HeapType::i31, Nullable) << "\n";
std::cout << Type(HeapType::i31, NonNullable) << "\n";
std::cout << Signature(Type::none, Type::none) << "\n";
Expand Down
76 changes: 38 additions & 38 deletions test/gtest/type-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1058,30 +1058,30 @@ TEST_F(TypeTest, TestDepth) {
}

// any :> eq :> array :> specific array types
EXPECT_EQ(HeapType(HeapType::any).getDepth(), 0U);
EXPECT_EQ(HeapType(HeapType::eq).getDepth(), 1U);
EXPECT_EQ(HeapType(HeapType::array).getDepth(), 2U);
EXPECT_EQ(HeapType(HeapType::struct_).getDepth(), 2U);
EXPECT_EQ(HeapTypes::any.getDepth(), 0U);
EXPECT_EQ(HeapTypes::eq.getDepth(), 1U);
EXPECT_EQ(HeapTypes::array.getDepth(), 2U);
EXPECT_EQ(HeapTypes::struct_.getDepth(), 2U);
EXPECT_EQ(A.getDepth(), 3U);
EXPECT_EQ(B.getDepth(), 4U);
EXPECT_EQ(C.getDepth(), 3U);

// Signature types are subtypes of func.
EXPECT_EQ(HeapType(HeapType::func).getDepth(), 0U);
EXPECT_EQ(HeapTypes::func.getDepth(), 0U);
EXPECT_EQ(sig.getDepth(), 1U);

// Continuation types are subtypes of cont.
EXPECT_EQ(HeapType(HeapType::cont).getDepth(), 0U);
EXPECT_EQ(HeapTypes::cont.getDepth(), 0U);
EXPECT_EQ(HeapType(Continuation(sig)).getDepth(), 1U);

EXPECT_EQ(HeapType(HeapType::ext).getDepth(), 0U);
EXPECT_EQ(HeapTypes::ext.getDepth(), 0U);

EXPECT_EQ(HeapType(HeapType::i31).getDepth(), 2U);
EXPECT_EQ(HeapType(HeapType::string).getDepth(), 2U);
EXPECT_EQ(HeapTypes::i31.getDepth(), 2U);
EXPECT_EQ(HeapTypes::string.getDepth(), 2U);

EXPECT_EQ(HeapType(HeapType::none).getDepth(), size_t(-1));
EXPECT_EQ(HeapType(HeapType::nofunc).getDepth(), size_t(-1));
EXPECT_EQ(HeapType(HeapType::noext).getDepth(), size_t(-1));
EXPECT_EQ(HeapTypes::none.getDepth(), size_t(-1));
EXPECT_EQ(HeapTypes::nofunc.getDepth(), size_t(-1));
EXPECT_EQ(HeapTypes::noext.getDepth(), size_t(-1));
}

// Test .iterSubTypes() helper.
Expand Down Expand Up @@ -1135,34 +1135,34 @@ TEST_F(TypeTest, TestIterSubTypes) {
// Test supertypes
TEST_F(TypeTest, TestSupertypes) {
// Basic types: getDeclaredSuperType always returns nothing.
ASSERT_FALSE(HeapType(HeapType::ext).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::func).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::cont).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::any).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::eq).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::i31).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::struct_).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::array).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::string).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::none).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::noext).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::nofunc).getDeclaredSuperType());
ASSERT_FALSE(HeapType(HeapType::nocont).getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::ext.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::func.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::cont.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::any.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::eq.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::i31.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::struct_.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::array.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::string.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::none.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::noext.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::nofunc.getDeclaredSuperType());
ASSERT_FALSE(HeapTypes::nocont.getDeclaredSuperType());

// Basic types: getSuperType does return a super, when there is one.
ASSERT_FALSE(HeapType(HeapType::ext).getSuperType());
ASSERT_FALSE(HeapType(HeapType::func).getSuperType());
ASSERT_FALSE(HeapType(HeapType::cont).getSuperType());
ASSERT_FALSE(HeapType(HeapType::any).getSuperType());
ASSERT_EQ(HeapType(HeapType::eq).getSuperType(), HeapType::any);
ASSERT_EQ(HeapType(HeapType::i31).getSuperType(), HeapType::eq);
ASSERT_EQ(HeapType(HeapType::struct_).getSuperType(), HeapType::eq);
ASSERT_EQ(HeapType(HeapType::array).getSuperType(), HeapType::eq);
ASSERT_FALSE(HeapType(HeapType::string).getSuperType());
ASSERT_FALSE(HeapType(HeapType::none).getSuperType());
ASSERT_FALSE(HeapType(HeapType::noext).getSuperType());
ASSERT_FALSE(HeapType(HeapType::nofunc).getSuperType());
ASSERT_FALSE(HeapType(HeapType::nocont).getSuperType());
ASSERT_FALSE(HeapTypes::ext.getSuperType());
ASSERT_FALSE(HeapTypes::func.getSuperType());
ASSERT_FALSE(HeapTypes::cont.getSuperType());
ASSERT_FALSE(HeapTypes::any.getSuperType());
ASSERT_EQ(HeapTypes::eq.getSuperType(), HeapType::any);
ASSERT_EQ(HeapTypes::i31.getSuperType(), HeapType::eq);
ASSERT_EQ(HeapTypes::struct_.getSuperType(), HeapType::eq);
ASSERT_EQ(HeapTypes::array.getSuperType(), HeapType::eq);
ASSERT_FALSE(HeapTypes::string.getSuperType());
ASSERT_FALSE(HeapTypes::none.getSuperType());
ASSERT_FALSE(HeapTypes::noext.getSuperType());
ASSERT_FALSE(HeapTypes::nofunc.getSuperType());
ASSERT_FALSE(HeapTypes::nocont.getSuperType());

// Non-basic types.
HeapType struct1, struct2, array1, array2, sig1, sig2;
Expand Down
47 changes: 47 additions & 0 deletions test/lit/basic/shared-types.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: wasm-opt %s -all -S -o - | filecheck %s
;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s

(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $final (shared (struct )))
(type $final (shared (struct)))
;; CHECK: (type $top (sub (shared (struct ))))
(type $top (sub (shared (struct))))
;; CHECK: (type $mid (sub $top (shared (struct (field i32)))))
(type $mid (sub $top (shared (struct i32))))
;; CHECK: (type $bot (sub final $mid (shared (struct (field i32) (field i32)))))
(type $bot (sub final $mid (shared (struct i32 i32))))

;; CHECK: (type $func (shared (func)))
(type $func (shared (func)))
;; CHECK: (type $array (shared (array i8)))
(type $array (shared (array i8)))
;; CHECK: (type $cont (shared (cont $func)))
(type $cont (shared (cont $func)))
)

;; CHECK: (type $7 (func))

;; CHECK: (func $use-types (type $7)
;; CHECK-NEXT: (local $0 (ref $final))
;; CHECK-NEXT: (local $1 (ref $top))
;; CHECK-NEXT: (local $2 (ref $mid))
;; CHECK-NEXT: (local $3 (ref $bot))
;; CHECK-NEXT: (local $4 (ref $func))
;; CHECK-NEXT: (local $5 (ref $array))
;; CHECK-NEXT: (local $6 (ref $cont))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $use-types
(local (ref $final))
(local (ref $top))
(local (ref $mid))
(local (ref $bot))
(local (ref $func))
(local (ref $array))
(local (ref $cont))
)
)
9 changes: 6 additions & 3 deletions test/lit/passes/type-merging-shared.wast
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,21 @@
(module
;; But two shared types can be merged.
;; CHECK: (rec
;; CHECK-NEXT: (type $B (shared (array i8)))
;; CHECK-NEXT: (type $C (shared (func)))

;; CHECK: (type $B (shared (array i8)))

;; CHECK: (type $A (shared (struct )))
(type $A (shared (struct)))
(type $A' (shared (struct)))
(type $B (shared (array i8)))
(type $B' (shared (array i8)))
;; CHECK: (type $C (shared (func)))
(type $C (shared (func)))
(type $C' (shared (func)))

;; CHECK: (func $foo (type $C)
;; CHECK: (type $3 (func))

;; CHECK: (func $foo (type $3)
;; CHECK-NEXT: (local $a (ref null $A))
;; CHECK-NEXT: (local $a' (ref null $A))
;; CHECK-NEXT: (local $b (ref null $B))
Expand Down