Skip to content

Commit c1a484e

Browse files
authored
[Custom Descriptors] Interpret ref.get_desc (#7675)
Add a descriptor to the GCData stored in a reference value. The descriptor itself is another literal representing either a null if there is no descriptor or otherwise a reference to the descriptor. Update the interpretation of struct.new to set the descriptor when allocating types with descriptors and then retrieve the descriptor when interpreting ref.get_desc.
1 parent 1898ec3 commit c1a484e

File tree

4 files changed

+60
-6
lines changed

4 files changed

+60
-6
lines changed

src/literal.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -775,8 +775,13 @@ struct GCData {
775775
// The element or field values.
776776
Literals values;
777777

778-
GCData(HeapType type, Literals&& values)
779-
: type(type), values(std::move(values)) {}
778+
// The descriptor, if it exists, or null.
779+
Literal desc;
780+
781+
GCData(HeapType type,
782+
Literals&& values,
783+
const Literal& desc = Literal::makeNull(HeapType::none))
784+
: type(type), values(std::move(values)), desc(desc) {}
780785
};
781786

782787
// The data of a (ref exn) literal.

src/wasm-interpreter.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,11 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
199199
// this function in LSan.
200200
//
201201
// This consumes the input |data| entirely.
202-
Literal makeGCData(Literals&& data, Type type) {
202+
Literal makeGCData(Literals&& data,
203+
Type type,
204+
Literal desc = Literal::makeNull(HeapType::none)) {
203205
auto allocation =
204-
std::make_shared<GCData>(type.getHeapType(), std::move(data));
206+
std::make_shared<GCData>(type.getHeapType(), std::move(data), desc);
205207
#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer)
206208
// GC data with cycles will leak, since shared_ptrs do not handle cycles.
207209
// Binaryen is generally not used in long-running programs so we just ignore
@@ -1673,7 +1675,15 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
16731675
}
16741676
Flow visitRefGetDesc(RefGetDesc* curr) {
16751677
NOTE_ENTER("RefGetDesc");
1676-
WASM_UNREACHABLE("unimplemented");
1678+
Flow ref = self()->visit(curr->ref);
1679+
if (ref.breaking()) {
1680+
return ref;
1681+
}
1682+
auto data = ref.getSingleValue().getGCData();
1683+
if (!data) {
1684+
trap("null ref");
1685+
}
1686+
return data->desc;
16771687
}
16781688
Flow visitBrOn(BrOn* curr) {
16791689
NOTE_ENTER("BrOn");
@@ -1742,6 +1752,12 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
17421752
return value;
17431753
}
17441754
}
1755+
if (curr->descriptor) {
1756+
auto value = self()->visit(curr->descriptor);
1757+
if (value.breaking()) {
1758+
return value;
1759+
}
1760+
}
17451761
WASM_UNREACHABLE("unreachable but no unreachable child");
17461762
}
17471763
auto heapType = curr->type.getHeapType();
@@ -1759,7 +1775,14 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
17591775
data[i] = truncateForPacking(value.getSingleValue(), field);
17601776
}
17611777
}
1762-
return makeGCData(std::move(data), curr->type);
1778+
if (!curr->descriptor) {
1779+
return makeGCData(std::move(data), curr->type);
1780+
}
1781+
auto desc = self()->visit(curr->descriptor);
1782+
if (desc.breaking()) {
1783+
return desc;
1784+
}
1785+
return makeGCData(std::move(data), curr->type, desc.getSingleValue());
17631786
}
17641787
Flow visitStructGet(StructGet* curr) {
17651788
NOTE_ENTER("StructGet");

src/wasm/wasm.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,9 @@ void StructNew::finalize() {
12161216
if (handleUnreachableOperands(this)) {
12171217
return;
12181218
}
1219+
if (descriptor && descriptor->type == Type::unreachable) {
1220+
type = Type::unreachable;
1221+
}
12191222
}
12201223

12211224
void StructGet::finalize() {

test/spec/ref.get_desc.wast

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
(type $struct (descriptor $desc (struct)))
44
(type $desc (describes $struct (struct)))
55
)
6+
7+
(global $desc1 (ref (exact $desc)) (struct.new $desc))
8+
(global $desc2 (ref (exact $desc)) (struct.new $desc))
9+
(global $struct1 (ref $struct) (struct.new $struct (global.get $desc1)))
10+
(global $struct2 (ref $struct) (struct.new $struct (global.get $desc2)))
11+
612
(func $unreachable (param $struct (ref null $struct)) (result (ref $desc))
713
(ref.get_desc $struct
814
(unreachable)
@@ -23,8 +29,25 @@
2329
(local.get $struct)
2430
)
2531
)
32+
33+
(func (export "check-descs") (result i32)
34+
(i32.and
35+
(i32.and
36+
(ref.eq (ref.get_desc $struct (global.get $struct1)) (global.get $desc1))
37+
(ref.eq (ref.get_desc $struct (global.get $struct2)) (global.get $desc2))
38+
)
39+
(i32.eqz (ref.eq (global.get $desc1) (global.get $desc2)))
40+
)
41+
)
42+
43+
(func (export "desc-trap") (result (ref $struct))
44+
(struct.new $struct (unreachable))
45+
)
2646
)
2747

48+
(assert_return (invoke "check-descs") (i32.const 1))
49+
(assert_trap (invoke "desc-trap") "unreachable")
50+
2851
(assert_invalid
2952
(module
3053
(rec

0 commit comments

Comments
 (0)