Skip to content

Commit 0402784

Browse files
authored
Support describes and descriptor clauses in the type system (#7369)
Update HeapTypeInfo, the rec group hashing and equality comparison utilities, the type canonicalization algorithm, and the TypeBuilder interface to support `describes` and `descriptor` clauses on heap type definitions. Parsing, the binary format, and validation for these clauses is left to future PRs.
1 parent 425d7c8 commit 0402784

File tree

3 files changed

+177
-1
lines changed

3 files changed

+177
-1
lines changed

src/wasm-type.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ class HeapType {
192192
// as well, just like |getDeclaredSuperType|.
193193
std::optional<HeapType> getSuperType() const;
194194

195+
// Get this type's descriptor or described types if they exist.
196+
std::optional<HeapType> getDescriptorType() const;
197+
std::optional<HeapType> getDescribedType() const;
198+
195199
// Return the depth of this heap type in the nominal type hierarchy, i.e. the
196200
// number of supertypes in its supertype chain.
197201
size_t getDepth() const;
@@ -712,6 +716,12 @@ struct TypeBuilder {
712716
if (auto super = type.getDeclaredSuperType()) {
713717
setSubType(i, map(*super));
714718
}
719+
if (auto desc = type.getDescriptorType()) {
720+
setDescriptor(i, map(*desc));
721+
}
722+
if (auto desc = type.getDescribedType()) {
723+
setDescribed(i, map(*desc));
724+
}
715725
setOpen(i, type.isOpen());
716726
setShared(i, type.getShared());
717727

@@ -782,6 +792,10 @@ struct TypeBuilder {
782792
// the given HeapType.
783793
void setSubType(size_t i, std::optional<HeapType> super);
784794

795+
// Set the descriptor or described type for the type at index `i`.
796+
void setDescriptor(size_t i, std::optional<HeapType> desc);
797+
void setDescribed(size_t i, std::optional<HeapType> desc);
798+
785799
// Create a new recursion group covering slots [i, i + length). Groups must
786800
// not overlap or go out of bounds.
787801
void createRecGroup(size_t i, size_t length);
@@ -858,6 +872,14 @@ struct TypeBuilder {
858872
builder.setSubType(index, other);
859873
return *this;
860874
}
875+
Entry& descriptor(std::optional<HeapType> other) {
876+
builder.setDescriptor(index, other);
877+
return *this;
878+
}
879+
Entry& describes(std::optional<HeapType> other) {
880+
builder.setDescribed(index, other);
881+
return *this;
882+
}
861883
Entry& setOpen(bool open = true) {
862884
builder.setOpen(index, open);
863885
return *this;

src/wasm/wasm-type.cpp

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ struct HeapTypeInfo {
5252
Shareability share = Unshared;
5353
// The supertype of this HeapType, if it exists.
5454
HeapTypeInfo* supertype = nullptr;
55+
// The descriptor of this HeapType, if it exists.
56+
HeapTypeInfo* descriptor = nullptr;
57+
// The HeapType described by this one, if it exists.
58+
HeapTypeInfo* described = nullptr;
5559
// The recursion group of this type or null if the recursion group is trivial
5660
// (i.e. contains only this type).
5761
RecGroupInfo* recGroup = nullptr;
@@ -976,6 +980,26 @@ std::optional<HeapType> HeapType::getSuperType() const {
976980
WASM_UNREACHABLE("unexpected kind");
977981
}
978982

983+
std::optional<HeapType> HeapType::getDescriptorType() const {
984+
if (isBasic()) {
985+
return std::nullopt;
986+
}
987+
if (auto* desc = getHeapTypeInfo(*this)->descriptor) {
988+
return HeapType(uintptr_t(desc));
989+
}
990+
return std::nullopt;
991+
}
992+
993+
std::optional<HeapType> HeapType::getDescribedType() const {
994+
if (isBasic()) {
995+
return std::nullopt;
996+
}
997+
if (auto* desc = getHeapTypeInfo(*this)->described) {
998+
return HeapType(uintptr_t(desc));
999+
}
1000+
return std::nullopt;
1001+
}
1002+
9791003
size_t HeapType::getDepth() const {
9801004
size_t depth = 0;
9811005
std::optional<HeapType> super;
@@ -1149,6 +1173,12 @@ std::vector<HeapType> HeapType::getReferencedHeapTypes() const {
11491173
if (auto super = getDeclaredSuperType()) {
11501174
types.push_back(*super);
11511175
}
1176+
if (auto desc = getDescriptorType()) {
1177+
types.push_back(*desc);
1178+
}
1179+
if (auto desc = getDescribedType()) {
1180+
types.push_back(*desc);
1181+
}
11521182
return types;
11531183
}
11541184

@@ -1280,6 +1310,10 @@ FeatureSet HeapType::getFeatures() const {
12801310
feats |= FeatureSet::ReferenceTypes | FeatureSet::GC;
12811311
}
12821312

1313+
if (heapType.getDescriptorType() || heapType.getDescribedType()) {
1314+
feats |= FeatureSet::CustomDescriptors;
1315+
}
1316+
12831317
if (heapType.isStruct() || heapType.isArray()) {
12841318
feats |= FeatureSet::ReferenceTypes | FeatureSet::GC;
12851319
} else if (heapType.isSignature()) {
@@ -1765,6 +1799,16 @@ std::ostream& TypePrinter::print(HeapType type) {
17651799
if (type.isShared()) {
17661800
os << "(shared ";
17671801
}
1802+
if (auto desc = type.getDescribedType()) {
1803+
os << "(describes ";
1804+
printHeapTypeName(*desc);
1805+
os << ' ';
1806+
}
1807+
if (auto desc = type.getDescriptorType()) {
1808+
os << "(descriptor ";
1809+
printHeapTypeName(*desc);
1810+
os << ' ';
1811+
}
17681812
switch (type.getKind()) {
17691813
case HeapTypeKind::Func:
17701814
print(type.getSignature());
@@ -1781,6 +1825,12 @@ std::ostream& TypePrinter::print(HeapType type) {
17811825
case HeapTypeKind::Basic:
17821826
WASM_UNREACHABLE("unexpected kind");
17831827
}
1828+
if (type.getDescriptorType()) {
1829+
os << ')';
1830+
}
1831+
if (type.getDescribedType()) {
1832+
os << ')';
1833+
}
17841834
if (type.isShared()) {
17851835
os << ')';
17861836
}
@@ -1927,9 +1977,18 @@ size_t RecGroupHasher::hash(HeapType type) const {
19271977

19281978
size_t RecGroupHasher::hash(const HeapTypeInfo& info) const {
19291979
size_t digest = wasm::hash(bool(info.supertype));
1980+
wasm::rehash(digest, !!info.supertype);
19301981
if (info.supertype) {
19311982
hash_combine(digest, hash(HeapType(uintptr_t(info.supertype))));
19321983
}
1984+
wasm::rehash(digest, !!info.descriptor);
1985+
if (info.descriptor) {
1986+
hash_combine(digest, hash(HeapType(uintptr_t(info.descriptor))));
1987+
}
1988+
wasm::rehash(digest, !!info.described);
1989+
if (info.described) {
1990+
hash_combine(digest, hash(HeapType(uintptr_t(info.described))));
1991+
}
19331992
wasm::rehash(digest, info.isOpen);
19341993
wasm::rehash(digest, info.share);
19351994
wasm::rehash(digest, info.kind);
@@ -2051,7 +2110,7 @@ bool RecGroupEquator::eq(HeapType a, HeapType b) const {
20512110
}
20522111

20532112
bool RecGroupEquator::eq(const HeapTypeInfo& a, const HeapTypeInfo& b) const {
2054-
if (bool(a.supertype) != bool(b.supertype)) {
2113+
if (!!a.supertype != !!b.supertype) {
20552114
return false;
20562115
}
20572116
if (a.supertype) {
@@ -2061,6 +2120,26 @@ bool RecGroupEquator::eq(const HeapTypeInfo& a, const HeapTypeInfo& b) const {
20612120
return false;
20622121
}
20632122
}
2123+
if (!!a.descriptor != !!b.descriptor) {
2124+
return false;
2125+
}
2126+
if (a.descriptor) {
2127+
HeapType descA(uintptr_t(a.descriptor));
2128+
HeapType descB(uintptr_t(b.descriptor));
2129+
if (!eq(descA, descB)) {
2130+
return false;
2131+
}
2132+
}
2133+
if (!!a.described != !!b.described) {
2134+
return false;
2135+
}
2136+
if (a.described) {
2137+
HeapType descA(uintptr_t(a.described));
2138+
HeapType descB(uintptr_t(b.described));
2139+
if (!eq(descA, descB)) {
2140+
return false;
2141+
}
2142+
}
20642143
if (a.isOpen != b.isOpen) {
20652144
return false;
20662145
}
@@ -2227,6 +2306,16 @@ void TypeBuilder::setSubType(size_t i, std::optional<HeapType> super) {
22272306
HeapTypeInfo* sub = impl->entries[i].info.get();
22282307
sub->supertype = super ? getHeapTypeInfo(*super) : nullptr;
22292308
}
2309+
void TypeBuilder::setDescriptor(size_t i, std::optional<HeapType> desc) {
2310+
assert(i < size() && "index out of bounds");
2311+
HeapTypeInfo* info = impl->entries[i].info.get();
2312+
info->descriptor = desc ? getHeapTypeInfo(*desc) : nullptr;
2313+
}
2314+
void TypeBuilder::setDescribed(size_t i, std::optional<HeapType> desc) {
2315+
assert(i < size() && "index out of bounds");
2316+
HeapTypeInfo* info = impl->entries[i].info.get();
2317+
info->described = desc ? getHeapTypeInfo(*desc) : nullptr;
2318+
}
22302319

22312320
void TypeBuilder::createRecGroup(size_t index, size_t length) {
22322321
assert(index <= size() && index + length <= size() && "group out of bounds");
@@ -2382,6 +2471,20 @@ void updateReferencedHeapTypes(
23822471
info->supertype = getHeapTypeInfo(it->second);
23832472
}
23842473
}
2474+
2475+
// Update the descriptor and described types.
2476+
if (info->descriptor) {
2477+
HeapType desc(uintptr_t(info->descriptor));
2478+
if (auto it = canonicalized.find(desc); it != canonicalized.end()) {
2479+
info->descriptor = getHeapTypeInfo(it->second);
2480+
}
2481+
}
2482+
if (info->described) {
2483+
HeapType desc(uintptr_t(info->described));
2484+
if (auto it = canonicalized.find(desc); it != canonicalized.end()) {
2485+
info->described = getHeapTypeInfo(it->second);
2486+
}
2487+
}
23852488
}
23862489

23872490
TypeBuilder::BuildResult

test/gtest/type-builder.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,57 @@ TEST_F(TypeTest, CanonicalizeSupertypes) {
504504
EXPECT_NE(built[4], built[5]);
505505
}
506506

507+
TEST_F(TypeTest, CanonicalizeDescriptors) {
508+
constexpr int numGroups = 3;
509+
constexpr int groupSize = 4;
510+
TypeBuilder builder(numGroups * groupSize);
511+
512+
for (int i = 0; i < numGroups; ++i) {
513+
builder.createRecGroup(i * groupSize, groupSize);
514+
}
515+
for (int i = 0; i < numGroups * groupSize; ++i) {
516+
builder[i] = Struct();
517+
}
518+
519+
// A B A' B'
520+
builder[0].descriptor(builder[1]);
521+
builder[1].describes(builder[0]);
522+
builder[2].descriptor(builder[3]);
523+
builder[3].describes(builder[2]);
524+
525+
// A' A B B'
526+
builder[4].descriptor(builder[7]);
527+
builder[5].descriptor(builder[6]);
528+
builder[6].describes(builder[5]);
529+
builder[7].describes(builder[4]);
530+
531+
auto translate = [&](HeapType t) -> HeapType {
532+
for (int i = 0; i < groupSize; ++i) {
533+
if (t == builder[i]) {
534+
return builder[2 * groupSize + i];
535+
}
536+
}
537+
WASM_UNREACHABLE("unexpected type");
538+
};
539+
540+
// A B A' B' again
541+
builder[8].copy(builder[0], translate);
542+
builder[9].copy(builder[1], translate);
543+
builder[10].copy(builder[2], translate);
544+
builder[11].copy(builder[3], translate);
545+
546+
auto result = builder.build();
547+
ASSERT_TRUE(result);
548+
auto built = *result;
549+
550+
EXPECT_EQ(built[0], built[8]);
551+
EXPECT_EQ(built[1], built[9]);
552+
EXPECT_EQ(built[2], built[10]);
553+
EXPECT_EQ(built[3], built[11]);
554+
555+
EXPECT_NE(built[0].getRecGroup(), built[4].getRecGroup());
556+
}
557+
507558
TEST_F(TypeTest, CanonicalizeFinal) {
508559
// Types are different if their finality flag is different.
509560
TypeBuilder builder(2);

0 commit comments

Comments
 (0)