Skip to content

Commit 862aeb9

Browse files
authored
Parse and emit exact heap types (#7432)
Implement text and binary parsing for exact heap types as well as binary emitting.
1 parent 570de79 commit 862aeb9

File tree

7 files changed

+102
-13
lines changed

7 files changed

+102
-13
lines changed

‎scripts/test/fuzzing.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@
113113
'vacuum-stack-switching.wast',
114114
# TODO: fuzzer support for custom descriptors
115115
'custom-descriptors.wast',
116+
# TODO: fuzzer support for exact heap types
117+
'exact.wast',
116118
]
117119

118120

‎src/parser/contexts.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ struct NullTypeParserCtx {
167167
Result<Index> getTypeIndex(Name) { return 1; }
168168
Result<HeapTypeT> getHeapTypeFromIdx(Index) { return Ok{}; }
169169

170+
HeapTypeT makeExact(HeapTypeT) { return Ok{}; }
171+
170172
DataStringT makeDataString() { return Ok{}; }
171173
void appendDataString(DataStringT&, std::string_view) {}
172174

@@ -251,6 +253,8 @@ template<typename Ctx> struct TypeParserCtx {
251253
return HeapTypes::nocont.getBasic(share);
252254
}
253255

256+
HeapTypeT makeExact(HeapTypeT type) { return type.with(Exact); }
257+
254258
TypeT makeI32() { return Type::i32; }
255259
TypeT makeI64() { return Type::i64; }
256260
TypeT makeF32() { return Type::f32; }

‎src/parser/parsers.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ Result<typename Ctx::HeapTypeT> absheaptype(Ctx& ctx, Shareability share) {
434434
}
435435

436436
// heaptype ::= x:typeidx => types[x]
437+
// | '(' 'exact' x:typeidx ')' => exact types[x]
437438
// | t:absheaptype => unshared t
438439
// | '(' 'shared' t:absheaptype ')' => shared t
439440
template<typename Ctx> Result<typename Ctx::HeapTypeT> heaptype(Ctx& ctx) {
@@ -442,6 +443,15 @@ template<typename Ctx> Result<typename Ctx::HeapTypeT> heaptype(Ctx& ctx) {
442443
return *t;
443444
}
444445

446+
if (ctx.in.takeSExprStart("exact"sv)) {
447+
auto t = typeidx(ctx);
448+
CHECK_ERR(t);
449+
if (!ctx.in.takeRParen()) {
450+
return ctx.in.err("expected end of exact heap type");
451+
}
452+
return ctx.makeExact(*t);
453+
}
454+
445455
auto share = ctx.in.takeSExprStart("shared"sv) ? Shared : Unshared;
446456
auto t = absheaptype(ctx, share);
447457
CHECK_ERR(t);

‎src/wasm-binary.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,8 @@ enum EncodedType {
343343
SubFinal = 0x4f,
344344
Shared = 0x65,
345345
SharedLEB = -0x1b, // Also 0x65 as an SLEB128
346+
Exact = 0x62,
347+
ExactLEB = -0x1e, // Also 0x62 as an SLEB128
346348
Rec = 0x4e,
347349
Descriptor = 0x4d,
348350
Describes = 0x4c,

‎src/wasm/wasm-binary.cpp

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ uint32_t WasmBinaryWriter::getElementSegmentIndex(Name name) const {
719719
}
720720

721721
uint32_t WasmBinaryWriter::getTypeIndex(HeapType type) const {
722-
auto it = indexedTypes.indices.find(type);
722+
auto it = indexedTypes.indices.find(type.with(Inexact));
723723
#ifndef NDEBUG
724724
if (it == indexedTypes.indices.end()) {
725725
std::cout << "Missing type: " << type << '\n';
@@ -1668,8 +1668,10 @@ void WasmBinaryWriter::writeHeapType(HeapType type) {
16681668
if (!wasm->features.hasGC()) {
16691669
type = type.getTop();
16701670
}
1671-
16721671
if (!type.isBasic()) {
1672+
if (type.isExact()) {
1673+
o << uint8_t(BinaryConsts::EncodedType::Exact);
1674+
}
16731675
o << S64LEB(getTypeIndex(type)); // TODO: Actually s33
16741676
return;
16751677
}
@@ -2183,12 +2185,20 @@ Type WasmBinaryReader::getType() { return getType(getS32LEB()); }
21832185

21842186
HeapType WasmBinaryReader::getHeapType() {
21852187
auto type = getS64LEB(); // TODO: Actually s33
2188+
auto exactness = Inexact;
2189+
if (type == BinaryConsts::EncodedType::ExactLEB) {
2190+
exactness = Exact;
2191+
type = getS64LEB(); // TODO: Actually s33
2192+
}
21862193
// Single heap types are negative; heap type indices are non-negative
21872194
if (type >= 0) {
21882195
if (size_t(type) >= types.size()) {
2189-
throwError("invalid signature index: " + std::to_string(type));
2196+
throwError("invalid type index: " + std::to_string(type));
21902197
}
2191-
return types[type];
2198+
return types[type].with(exactness);
2199+
}
2200+
if (exactness == Exact) {
2201+
throwError("invalid type index: " + std::to_string(type));
21922202
}
21932203
auto share = Unshared;
21942204
if (type == BinaryConsts::EncodedType::SharedLEB) {
@@ -2198,10 +2208,8 @@ HeapType WasmBinaryReader::getHeapType() {
21982208
HeapType ht;
21992209
if (getBasicHeapType(type, ht)) {
22002210
return ht.getBasic(share);
2201-
} else {
2202-
throwError("invalid wasm heap type: " + std::to_string(type));
22032211
}
2204-
WASM_UNREACHABLE("unexpected type");
2212+
throwError("invalid wasm heap type: " + std::to_string(type));
22052213
}
22062214

22072215
HeapType WasmBinaryReader::getIndexedHeapType() {
@@ -2325,6 +2333,20 @@ void WasmBinaryReader::readTypes() {
23252333

23262334
auto readHeapType = [&]() -> HeapType {
23272335
int64_t htCode = getS64LEB(); // TODO: Actually s33
2336+
auto exactness = Inexact;
2337+
if (htCode == BinaryConsts::EncodedType::ExactLEB) {
2338+
exactness = Exact;
2339+
htCode = getS64LEB(); // TODO: Actually s33
2340+
}
2341+
if (htCode >= 0) {
2342+
if (size_t(htCode) >= builder.size()) {
2343+
throwError("invalid type index: " + std::to_string(htCode));
2344+
}
2345+
return builder.getTempHeapType(size_t(htCode)).with(exactness);
2346+
}
2347+
if (exactness == Exact) {
2348+
throwError("invalid type index: " + std::to_string(htCode));
2349+
}
23282350
auto share = Unshared;
23292351
if (htCode == BinaryConsts::EncodedType::SharedLEB) {
23302352
share = Shared;
@@ -2334,10 +2356,7 @@ void WasmBinaryReader::readTypes() {
23342356
if (getBasicHeapType(htCode, ht)) {
23352357
return ht.getBasic(share);
23362358
}
2337-
if (size_t(htCode) >= builder.size()) {
2338-
throwError("invalid type index: " + std::to_string(htCode));
2339-
}
2340-
return builder.getTempHeapType(size_t(htCode));
2359+
throwError("invalid wasm heap type: " + std::to_string(htCode));
23412360
};
23422361
auto makeType = [&](int32_t typeCode) {
23432362
Type type;

‎src/wasm/wasm-type.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,9 +1621,9 @@ void TypePrinter::printHeapTypeName(HeapType type) {
16211621
if (type.isBasic()) {
16221622
print(type);
16231623
} else {
1624-
generator(type).name.print(os);
1624+
generator(type.with(Inexact)).name.print(os);
16251625
#if TRACE_CANONICALIZATION
1626-
os << "(;" << ((type.getID() >> 4) % 1000) << ";) ";
1626+
os << "(;" << ((type.with(Inexact).getID() >> 4) % 1000) << ";) ";
16271627
#endif
16281628
}
16291629
if (type.isExact()) {

‎test/lit/basic/exact.wast

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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 $a (struct (field (ref null (exact $a))) (field (ref (exact $b)))))
16+
;; CHECK-BIN: (rec
17+
;; CHECK-BIN-NEXT: (type $a (struct (field (ref null (exact $a))) (field (ref (exact $b)))))
18+
(type $a (struct (field (ref null (exact 0)) (ref (exact 1)))))
19+
;; CHECK-TEXT: (type $b (struct (field (ref (exact $a))) (field (ref null (exact $b)))))
20+
;; CHECK-BIN: (type $b (struct (field (ref (exact $a))) (field (ref null (exact $b)))))
21+
(type $b (struct (field (ref (exact $a)) (ref null (exact $b)))))
22+
)
23+
24+
;; CHECK-TEXT: (type $2 (func (param (ref null (exact $a)) (ref (exact $b))) (result (ref (exact $a)) (ref null (exact $b)))))
25+
26+
;; CHECK-TEXT: (func $foo (type $2) (param $0 (ref null (exact $a))) (param $1 (ref (exact $b))) (result (ref (exact $a)) (ref null (exact $b)))
27+
;; CHECK-TEXT-NEXT: (local $2 (ref null (exact $a)))
28+
;; CHECK-TEXT-NEXT: (unreachable)
29+
;; CHECK-TEXT-NEXT: )
30+
;; CHECK-BIN: (type $2 (func (param (ref null (exact $a)) (ref (exact $b))) (result (ref (exact $a)) (ref null (exact $b)))))
31+
32+
;; CHECK-BIN: (func $foo (type $2) (param $0 (ref null (exact $a))) (param $1 (ref (exact $b))) (result (ref (exact $a)) (ref null (exact $b)))
33+
;; CHECK-BIN-NEXT: (local $2 (ref null (exact $a)))
34+
;; CHECK-BIN-NEXT: (unreachable)
35+
;; CHECK-BIN-NEXT: )
36+
(func $foo (param (ref null (exact $a)) (ref (exact $b)))
37+
(result (ref (exact $a)) (ref null (exact $b)))
38+
(local (ref null (exact $a)))
39+
(unreachable)
40+
)
41+
)
42+
;; CHECK-BIN-NODEBUG: (rec
43+
;; CHECK-BIN-NODEBUG-NEXT: (type $0 (struct (field (ref null (exact $0))) (field (ref (exact $1)))))
44+
45+
;; CHECK-BIN-NODEBUG: (type $1 (struct (field (ref (exact $0))) (field (ref null (exact $1)))))
46+
47+
;; CHECK-BIN-NODEBUG: (type $2 (func (param (ref null (exact $0)) (ref (exact $1))) (result (ref (exact $0)) (ref null (exact $1)))))
48+
49+
;; CHECK-BIN-NODEBUG: (func $0 (type $2) (param $0 (ref null (exact $0))) (param $1 (ref (exact $1))) (result (ref (exact $0)) (ref null (exact $1)))
50+
;; CHECK-BIN-NODEBUG-NEXT: (local $2 (ref null (exact $0)))
51+
;; CHECK-BIN-NODEBUG-NEXT: (unreachable)
52+
;; CHECK-BIN-NODEBUG-NEXT: )

0 commit comments

Comments
 (0)