Skip to content

Commit bd59ac6

Browse files
authored
Binary encoding and decoding of exact casts (#7347)
The binary format for casts needs to be extended to support exact references. In particular, add new opcodes for `ref.test` and `ref.cast` that take reference type immediates instead of heap type immediates. Use two more bits in the flags immediate of `br_on_cast` and `br_on_cast_fail` to encode the source and destination exactness.
1 parent d81f5bb commit bd59ac6

File tree

4 files changed

+442
-14
lines changed

4 files changed

+442
-14
lines changed

src/wasm-binary.h

+9
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,13 @@ enum SegmentFlag {
304304
UsesExpressions = 1 << 2
305305
};
306306

307+
enum BrOnCastFlag {
308+
InputNullable = 1 << 0,
309+
OutputNullable = 1 << 1,
310+
InputExact = 1 << 2,
311+
OutputExact = 1 << 3,
312+
};
313+
307314
enum EncodedType {
308315
// value types
309316
i32 = -0x1, // 0x7f
@@ -1126,6 +1133,8 @@ enum ASTNodes {
11261133
I31GetS = 0x1d,
11271134
I31GetU = 0x1e,
11281135
RefI31Shared = 0x1f,
1136+
RefTestRT = 0x20,
1137+
RefCastRT = 0x21,
11291138

11301139
// Shared GC Opcodes
11311140

src/wasm/wasm-binary.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -4251,16 +4251,30 @@ Result<> WasmBinaryReader::readInst() {
42514251
return builder.makeRefTest(Type(getHeapType(), NonNullable));
42524252
case BinaryConsts::RefTestNull:
42534253
return builder.makeRefTest(Type(getHeapType(), Nullable));
4254+
case BinaryConsts::RefTestRT:
4255+
return builder.makeRefTest(getType());
42544256
case BinaryConsts::RefCast:
42554257
return builder.makeRefCast(Type(getHeapType(), NonNullable));
42564258
case BinaryConsts::RefCastNull:
42574259
return builder.makeRefCast(Type(getHeapType(), Nullable));
4260+
case BinaryConsts::RefCastRT:
4261+
return builder.makeRefCast(getType());
42584262
case BinaryConsts::BrOnCast:
42594263
case BinaryConsts::BrOnCastFail: {
42604264
auto flags = getInt8();
42614265
auto label = getU32LEB();
4262-
auto in = Type(getHeapType(), (flags & 1) ? Nullable : NonNullable);
4263-
auto cast = Type(getHeapType(), (flags & 2) ? Nullable : NonNullable);
4266+
auto srcNull = (flags & BinaryConsts::BrOnCastFlag::InputNullable)
4267+
? Nullable
4268+
: NonNullable;
4269+
auto dstNull = (flags & BinaryConsts::BrOnCastFlag::OutputNullable)
4270+
? Nullable
4271+
: NonNullable;
4272+
auto srcExact =
4273+
(flags & BinaryConsts::BrOnCastFlag::InputExact) ? Exact : Inexact;
4274+
auto dstExact =
4275+
(flags & BinaryConsts::BrOnCastFlag::OutputExact) ? Exact : Inexact;
4276+
auto in = Type(getHeapType(), srcNull, srcExact);
4277+
auto cast = Type(getHeapType(), dstNull, dstExact);
42644278
auto kind = op == BinaryConsts::BrOnCast ? BrOnCast : BrOnCastFail;
42654279
return builder.makeBrOn(label, kind, in, cast);
42664280
}

src/wasm/wasm-stack.cpp

+42-10
Original file line numberDiff line numberDiff line change
@@ -2260,22 +2260,38 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) {
22602260

22612261
void BinaryInstWriter::visitRefTest(RefTest* curr) {
22622262
o << int8_t(BinaryConsts::GCPrefix);
2263-
if (curr->castType.isNullable()) {
2264-
o << U32LEB(BinaryConsts::RefTestNull);
2263+
if (curr->castType.isExact() &&
2264+
parent.getModule()->features.hasCustomDescriptors()) {
2265+
// Fall back to the general form with a reftype immediate.
2266+
o << U32LEB(BinaryConsts::RefTestRT);
2267+
parent.writeType(curr->castType);
22652268
} else {
2266-
o << U32LEB(BinaryConsts::RefTest);
2269+
// Use the special-case form with heap type immediate.
2270+
if (curr->castType.isNullable()) {
2271+
o << U32LEB(BinaryConsts::RefTestNull);
2272+
} else {
2273+
o << U32LEB(BinaryConsts::RefTest);
2274+
}
2275+
parent.writeHeapType(curr->castType.getHeapType());
22672276
}
2268-
parent.writeHeapType(curr->castType.getHeapType());
22692277
}
22702278

22712279
void BinaryInstWriter::visitRefCast(RefCast* curr) {
22722280
o << int8_t(BinaryConsts::GCPrefix);
2273-
if (curr->type.isNullable()) {
2274-
o << U32LEB(BinaryConsts::RefCastNull);
2281+
if (curr->type.isExact() &&
2282+
parent.getModule()->features.hasCustomDescriptors()) {
2283+
// Fall back to the general form with a reftype immediate.
2284+
o << U32LEB(BinaryConsts::RefCastRT);
2285+
parent.writeType(curr->type);
22752286
} else {
2276-
o << U32LEB(BinaryConsts::RefCast);
2287+
// Use the special-case form with heap type immediate.
2288+
if (curr->type.isNullable()) {
2289+
o << U32LEB(BinaryConsts::RefCastNull);
2290+
} else {
2291+
o << U32LEB(BinaryConsts::RefCast);
2292+
}
2293+
parent.writeHeapType(curr->type.getHeapType());
22772294
}
2278-
parent.writeHeapType(curr->type.getHeapType());
22792295
}
22802296

22812297
void BinaryInstWriter::visitBrOn(BrOn* curr) {
@@ -2298,8 +2314,24 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) {
22982314
}
22992315
assert(curr->ref->type.isRef());
23002316
assert(Type::isSubType(curr->castType, curr->ref->type));
2301-
uint8_t flags = (curr->ref->type.isNullable() ? 1 : 0) |
2302-
(curr->castType.isNullable() ? 2 : 0);
2317+
uint8_t flags = 0;
2318+
if (curr->ref->type.isNullable()) {
2319+
flags |= BinaryConsts::BrOnCastFlag::InputNullable;
2320+
}
2321+
if (curr->castType.isNullable()) {
2322+
flags |= BinaryConsts::BrOnCastFlag::OutputNullable;
2323+
}
2324+
if (parent.getModule()->features.hasCustomDescriptors()) {
2325+
// If custom descriptors (and therefore exact references) are not
2326+
// enabled, then these flags wouldn't be recognized, and we will be
2327+
// generalizing all exact references to be non-exact anyway.
2328+
if (curr->ref->type.isExact()) {
2329+
flags |= BinaryConsts::BrOnCastFlag::InputExact;
2330+
}
2331+
if (curr->castType.isExact()) {
2332+
flags |= BinaryConsts::BrOnCastFlag::OutputExact;
2333+
}
2334+
}
23032335
o << flags;
23042336
o << U32LEB(getBreakIndex(curr->name));
23052337
parent.writeHeapType(curr->ref->type.getHeapType());

0 commit comments

Comments
 (0)