Skip to content

Commit 7508e81

Browse files
authored
Parsing and binary writing for custom descriptors (#7387)
Implement text and binary parsing as well as binary writing for `descriptor` and `describes` clauses, as specified in the custom-descriptors proposal. Also simplify some neighboring code dealing with shared types as a drive-by.
1 parent 835a178 commit 7508e81

File tree

6 files changed

+148
-28
lines changed

6 files changed

+148
-28
lines changed

scripts/test/fuzzing.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@
109109
'coalesce-locals-exact.wast',
110110
'remove-unused-brs-exact.wast',
111111
'exact.wast',
112+
# TODO: fuzzer support for custom descriptors
113+
'custom-descriptors.wast',
112114
]
113115

114116

src/parser/contexts.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,9 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
982982
void addArrayType(ArrayT) {}
983983
void setOpen() {}
984984
void setShared() {}
985-
Result<> addSubtype(HeapTypeT) { return Ok{}; }
985+
void setDescribes(HeapTypeT) {}
986+
void setDescriptor(HeapTypeT) {}
987+
void setSupertype(HeapTypeT) {}
986988
void finishTypeDef(Name name, Index pos) {
987989
// TODO: type annotations
988990
typeDefs.push_back({name, pos, Index(typeDefs.size()), {}});
@@ -1157,10 +1159,11 @@ struct ParseTypeDefsCtx : TypeParserCtx<ParseTypeDefsCtx> {
11571159

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

1160-
Result<> addSubtype(HeapTypeT super) {
1161-
builder[index].subTypeOf(super);
1162-
return Ok{};
1163-
}
1162+
void setDescribes(HeapTypeT desc) { builder[index].describes(desc); }
1163+
1164+
void setDescriptor(HeapTypeT desc) { builder[index].descriptor(desc); }
1165+
1166+
void setSupertype(HeapTypeT super) { builder[index].subTypeOf(super); }
11641167

11651168
void finishTypeDef(Name name, Index pos) { names[index++].name = name; }
11661169

src/parser/parsers.h

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ Result<typename Ctx::TypeUseT> typeuse(Ctx&, bool allowNames = true);
357357
MaybeResult<ImportNames> inlineImport(Lexer&);
358358
Result<std::vector<Name>> inlineExports(Lexer&);
359359
template<typename Ctx> Result<> comptype(Ctx&);
360+
template<typename Ctx> Result<> describedcomptype(Ctx&);
361+
template<typename Ctx> Result<> describingcomptype(Ctx&);
360362
template<typename Ctx> Result<> sharecomptype(Ctx&);
361363
template<typename Ctx> Result<> subtype(Ctx&);
362364
template<typename Ctx> MaybeResult<> typedef_(Ctx&);
@@ -2940,19 +2942,50 @@ template<typename Ctx> Result<> comptype(Ctx& ctx) {
29402942
return ctx.in.err("expected type description");
29412943
}
29422944

2943-
// sharecomptype ::= '(' 'shared' t:comptype ')' => shared t
2944-
// | t:comptype => unshared t
2945+
// describedcomptype ::= '(' 'descriptor' typeidx ct:comptype ')'
2946+
// | ct:comptype
2947+
template<typename Ctx> Result<> describedcomptype(Ctx& ctx) {
2948+
if (ctx.in.takeSExprStart("descriptor"sv)) {
2949+
auto x = typeidx(ctx);
2950+
CHECK_ERR(x);
2951+
ctx.setDescriptor(*x);
2952+
CHECK_ERR(comptype(ctx));
2953+
if (!ctx.in.takeRParen()) {
2954+
return ctx.in.err("expected end of described type");
2955+
}
2956+
return Ok{};
2957+
}
2958+
return comptype(ctx);
2959+
}
2960+
2961+
// describingcomptype ::= '(' 'describes' typeidx ct:describedcomptype ')'
2962+
// | ct: describedcomptype
2963+
template<typename Ctx> Result<> describingcomptype(Ctx& ctx) {
2964+
if (ctx.in.takeSExprStart("describes"sv)) {
2965+
auto x = typeidx(ctx);
2966+
CHECK_ERR(x);
2967+
ctx.setDescribes(*x);
2968+
CHECK_ERR(describedcomptype(ctx));
2969+
if (!ctx.in.takeRParen()) {
2970+
return ctx.in.err("expected end of describing type");
2971+
}
2972+
return Ok{};
2973+
}
2974+
return describedcomptype(ctx);
2975+
}
2976+
2977+
// sharecomptype ::= '(' 'shared' t:describingcomptype ')' => shared t
2978+
// | t:describingcomptype => unshared t
29452979
template<typename Ctx> Result<> sharecomptype(Ctx& ctx) {
29462980
if (ctx.in.takeSExprStart("shared"sv)) {
29472981
ctx.setShared();
2948-
CHECK_ERR(comptype(ctx));
2982+
CHECK_ERR(describingcomptype(ctx));
29492983
if (!ctx.in.takeRParen()) {
29502984
return ctx.in.err("expected end of shared comptype");
29512985
}
2952-
} else {
2953-
CHECK_ERR(comptype(ctx));
2986+
return Ok{};
29542987
}
2955-
return Ok{};
2988+
return describingcomptype(ctx);
29562989
}
29572990

29582991
// subtype ::= '(' 'sub' typeidx? sharecomptype ')' | sharecomptype
@@ -2963,7 +2996,7 @@ template<typename Ctx> Result<> subtype(Ctx& ctx) {
29632996
}
29642997
if (auto super = maybeTypeidx(ctx)) {
29652998
CHECK_ERR(super);
2966-
CHECK_ERR(ctx.addSubtype(*super));
2999+
ctx.setSupertype(*super);
29673000
}
29683001

29693002
CHECK_ERR(sharecomptype(ctx));

src/wasm-binary.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,11 @@ enum EncodedType {
349349
Array = 0x5e,
350350
Sub = 0x50,
351351
SubFinal = 0x4f,
352-
SharedDef = 0x65,
353-
Shared = -0x1b, // Also 0x65 as an SLEB128
352+
Shared = 0x65,
353+
SharedLEB = -0x1b, // Also 0x65 as an SLEB128
354354
Rec = 0x4e,
355+
Descriptor = 0x4d,
356+
Describes = 0x4c,
355357
// block_type
356358
Empty = -0x40, // 0x40
357359
};

src/wasm/wasm-binary.cpp

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,15 @@ void WasmBinaryWriter::writeTypes() {
285285
}
286286
}
287287
if (type.isShared()) {
288-
o << uint8_t(BinaryConsts::EncodedType::SharedDef);
288+
o << uint8_t(BinaryConsts::EncodedType::Shared);
289+
}
290+
if (auto desc = type.getDescribedType()) {
291+
o << uint8_t(BinaryConsts::EncodedType::Describes);
292+
writeHeapType(*desc);
293+
}
294+
if (auto desc = type.getDescriptorType()) {
295+
o << uint8_t(BinaryConsts::EncodedType::Descriptor);
296+
writeHeapType(*desc);
289297
}
290298
switch (type.getKind()) {
291299
case HeapTypeKind::Func: {
@@ -1680,7 +1688,7 @@ void WasmBinaryWriter::writeHeapType(HeapType type) {
16801688

16811689
int ret = 0;
16821690
if (type.isShared()) {
1683-
o << S32LEB(BinaryConsts::EncodedType::Shared);
1691+
o << uint8_t(BinaryConsts::EncodedType::Shared);
16841692
}
16851693
switch (type.getBasic(Unshared)) {
16861694
case HeapType::ext:
@@ -2206,7 +2214,7 @@ HeapType WasmBinaryReader::getHeapType() {
22062214
return types[type];
22072215
}
22082216
auto share = Unshared;
2209-
if (type == BinaryConsts::EncodedType::Shared) {
2217+
if (type == BinaryConsts::EncodedType::SharedLEB) {
22102218
share = Shared;
22112219
type = getS64LEB(); // TODO: Actually s33
22122220
}
@@ -2341,7 +2349,7 @@ void WasmBinaryReader::readTypes() {
23412349
auto readHeapType = [&]() -> HeapType {
23422350
int64_t htCode = getS64LEB(); // TODO: Actually s33
23432351
auto share = Unshared;
2344-
if (htCode == BinaryConsts::EncodedType::Shared) {
2352+
if (htCode == BinaryConsts::EncodedType::SharedLEB) {
23452353
share = Shared;
23462354
htCode = getS64LEB(); // TODO: Actually s33
23472355
}
@@ -2467,7 +2475,6 @@ void WasmBinaryReader::readTypes() {
24672475
builder.createRecGroup(i, groupSize);
24682476
form = getInt8();
24692477
}
2470-
std::optional<uint32_t> superIndex;
24712478
if (form == BinaryConsts::EncodedType::Sub ||
24722479
form == BinaryConsts::EncodedType::SubFinal) {
24732480
if (form == BinaryConsts::EncodedType::Sub) {
@@ -2479,14 +2486,34 @@ void WasmBinaryReader::readTypes() {
24792486
throwError("Invalid type definition with " + std::to_string(supers) +
24802487
" supertypes");
24812488
}
2482-
superIndex = getU32LEB();
2489+
auto superIdx = getU32LEB();
2490+
if (superIdx >= builder.size()) {
2491+
throwError("invalid supertype index: " + std::to_string(superIdx));
2492+
}
2493+
builder[i].subTypeOf(builder[superIdx]);
24832494
}
24842495
form = getInt8();
24852496
}
2486-
if (form == BinaryConsts::SharedDef) {
2497+
if (form == BinaryConsts::EncodedType::Shared) {
24872498
builder[i].setShared();
24882499
form = getInt8();
24892500
}
2501+
if (form == BinaryConsts::EncodedType::Describes) {
2502+
auto descIdx = getU32LEB();
2503+
if (descIdx >= builder.size()) {
2504+
throwError("invalid described type index: " + std::to_string(descIdx));
2505+
}
2506+
builder[i].describes(builder[descIdx]);
2507+
form = getInt8();
2508+
}
2509+
if (form == BinaryConsts::EncodedType::Descriptor) {
2510+
auto descIdx = getU32LEB();
2511+
if (descIdx >= builder.size()) {
2512+
throwError("invalid descriptor type index: " + std::to_string(descIdx));
2513+
}
2514+
builder[i].descriptor(builder[descIdx]);
2515+
form = getInt8();
2516+
}
24902517
if (form == BinaryConsts::EncodedType::Func) {
24912518
builder[i] = readSignatureDef();
24922519
} else if (form == BinaryConsts::EncodedType::Cont) {
@@ -2498,13 +2525,6 @@ void WasmBinaryReader::readTypes() {
24982525
} else {
24992526
throwError("Bad type form " + std::to_string(form));
25002527
}
2501-
if (superIndex) {
2502-
if (*superIndex > builder.size()) {
2503-
throwError("Out of bounds supertype index " +
2504-
std::to_string(*superIndex));
2505-
}
2506-
builder[i].subTypeOf(builder[*superIndex]);
2507-
}
25082528
}
25092529

25102530
auto result = builder.build();
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
3+
;; RUN: wasm-opt %s -all -o %t.text.wast -g -S
4+
;; RUN: wasm-as %s -all -g -o %t.wasm
5+
;; RUN: wasm-dis %t.wasm -all -o %t.bin.wast
6+
;; RUN: wasm-as %s -all -o %t.nodebug.wasm
7+
;; RUN: wasm-dis %t.nodebug.wasm -all -o %t.bin.nodebug.wast
8+
;; RUN: cat %t.text.wast | filecheck %s --check-prefix=CHECK-TEXT
9+
;; RUN: cat %t.bin.wast | filecheck %s --check-prefix=CHECK-BIN
10+
;; RUN: cat %t.bin.nodebug.wast | filecheck %s --check-prefix=CHECK-BIN-NODEBUG
11+
12+
(module
13+
(rec
14+
;; CHECK-TEXT: (rec
15+
;; CHECK-TEXT-NEXT: (type $described (descriptor $middle (struct)))
16+
;; CHECK-BIN: (rec
17+
;; CHECK-BIN-NEXT: (type $described (descriptor $middle (struct)))
18+
(type $described (descriptor $middle (struct)))
19+
;; CHECK-TEXT: (type $middle (describes $described (descriptor $describing (struct))))
20+
;; CHECK-BIN: (type $middle (describes $described (descriptor $describing (struct))))
21+
(type $middle (describes $described (descriptor $describing (struct))))
22+
;; CHECK-TEXT: (type $describing (describes $middle (struct)))
23+
;; CHECK-BIN: (type $describing (describes $middle (struct)))
24+
(type $describing (describes $middle (struct)))
25+
)
26+
27+
(rec
28+
;; CHECK-TEXT: (rec
29+
;; CHECK-TEXT-NEXT: (type $shared-described (shared (descriptor $shared-describing (struct))))
30+
;; CHECK-BIN: (rec
31+
;; CHECK-BIN-NEXT: (type $shared-described (shared (descriptor $shared-describing (struct))))
32+
(type $shared-described (shared (descriptor $shared-describing (struct))))
33+
;; CHECK-TEXT: (type $shared-describing (shared (describes $shared-described (struct))))
34+
;; CHECK-BIN: (type $shared-describing (shared (describes $shared-described (struct))))
35+
(type $shared-describing (shared (describes $shared-described (struct))))
36+
)
37+
38+
39+
;; CHECK-TEXT: (global $g (ref null $described) (ref.null none))
40+
;; CHECK-BIN: (global $g (ref null $described) (ref.null none))
41+
(global $g (ref null $described) (ref.null none))
42+
;; CHECK-TEXT: (global $shared (ref null $shared-describing) (ref.null (shared none)))
43+
;; CHECK-BIN: (global $shared (ref null $shared-describing) (ref.null (shared none)))
44+
(global $shared (ref null $shared-describing) (ref.null (shared none)))
45+
)
46+
;; CHECK-BIN-NODEBUG: (rec
47+
;; CHECK-BIN-NODEBUG-NEXT: (type $0 (descriptor $1 (struct)))
48+
49+
;; CHECK-BIN-NODEBUG: (type $1 (describes $0 (descriptor $2 (struct))))
50+
51+
;; CHECK-BIN-NODEBUG: (type $2 (describes $1 (struct)))
52+
53+
;; CHECK-BIN-NODEBUG: (rec
54+
;; CHECK-BIN-NODEBUG-NEXT: (type $3 (shared (descriptor $4 (struct))))
55+
56+
;; CHECK-BIN-NODEBUG: (type $4 (shared (describes $3 (struct))))
57+
58+
;; CHECK-BIN-NODEBUG: (global $global$0 (ref null $0) (ref.null none))
59+
60+
;; CHECK-BIN-NODEBUG: (global $global$1 (ref null $4) (ref.null (shared none)))

0 commit comments

Comments
 (0)