@@ -279,7 +279,7 @@ void WasmBinaryWriter::writeTypes() {
279
279
}
280
280
if (super) {
281
281
o << U32LEB (1 );
282
- writeHeapType (*super);
282
+ writeHeapType (*super, Inexact );
283
283
} else {
284
284
o << U32LEB (0 );
285
285
}
@@ -289,11 +289,11 @@ void WasmBinaryWriter::writeTypes() {
289
289
}
290
290
if (auto desc = type.getDescribedType ()) {
291
291
o << uint8_t (BinaryConsts::EncodedType::Describes);
292
- writeHeapType (*desc);
292
+ writeHeapType (*desc, Inexact );
293
293
}
294
294
if (auto desc = type.getDescriptorType ()) {
295
295
o << uint8_t (BinaryConsts::EncodedType::Descriptor);
296
- writeHeapType (*desc);
296
+ writeHeapType (*desc, Inexact );
297
297
}
298
298
switch (type.getKind ()) {
299
299
case HeapTypeKind::Func: {
@@ -322,7 +322,7 @@ void WasmBinaryWriter::writeTypes() {
322
322
break ;
323
323
case HeapTypeKind::Cont:
324
324
o << uint8_t (BinaryConsts::EncodedType::Cont);
325
- writeHeapType (type.getContinuation ().type );
325
+ writeHeapType (type.getContinuation ().type , Inexact );
326
326
break ;
327
327
case HeapTypeKind::Basic:
328
328
WASM_UNREACHABLE (" unexpected kind" );
@@ -1574,12 +1574,6 @@ void WasmBinaryWriter::writeInlineBuffer(const char* data, size_t size) {
1574
1574
1575
1575
void WasmBinaryWriter::writeType (Type type) {
1576
1576
if (type.isRef ()) {
1577
- // Exact references are introduced by the custom descriptors feature, but
1578
- // can be used internally even when it is not enabled. In that case, we have
1579
- // to generalize the types to be inexact before writing them.
1580
- if (!wasm->features .hasCustomDescriptors ()) {
1581
- type = Type (type.getHeapType (), type.getNullability (), Inexact);
1582
- }
1583
1577
// The only reference types allowed without GC are funcref, externref, and
1584
1578
// exnref. We internally use more refined versions of those types, but we
1585
1579
// cannot emit those without GC.
@@ -1596,12 +1590,6 @@ void WasmBinaryWriter::writeType(Type type) {
1596
1590
type = Type (type.getHeapType ().getTop (), Nullable);
1597
1591
}
1598
1592
}
1599
- // If the type is exact, emit the exact prefix and continue on without
1600
- // considering exactness.
1601
- if (type.isExact ()) {
1602
- o << S32LEB (BinaryConsts::EncodedType::exact);
1603
- type = Type (type.getHeapType (), type.getNullability (), Inexact);
1604
- }
1605
1593
auto heapType = type.getHeapType ();
1606
1594
if (type.isNullable () && heapType.isBasic () && !heapType.isShared ()) {
1607
1595
switch (heapType.getBasic (Unshared)) {
@@ -1657,7 +1645,7 @@ void WasmBinaryWriter::writeType(Type type) {
1657
1645
} else {
1658
1646
o << S32LEB (BinaryConsts::EncodedType::nonnullable);
1659
1647
}
1660
- writeHeapType (type.getHeapType ());
1648
+ writeHeapType (type.getHeapType (), type. getExactness () );
1661
1649
return ;
1662
1650
}
1663
1651
int ret = 0 ;
@@ -1688,14 +1676,20 @@ void WasmBinaryWriter::writeType(Type type) {
1688
1676
o << S32LEB (ret);
1689
1677
}
1690
1678
1691
- void WasmBinaryWriter::writeHeapType (HeapType type) {
1679
+ void WasmBinaryWriter::writeHeapType (HeapType type, Exactness exactness ) {
1692
1680
// ref.null always has a bottom heap type in Binaryen IR, but those types are
1693
1681
// only actually valid with GC. Otherwise, emit the corresponding valid top
1694
1682
// types instead.
1683
+ if (!wasm->features .hasCustomDescriptors ()) {
1684
+ exactness = Inexact;
1685
+ }
1695
1686
if (!wasm->features .hasGC ()) {
1696
1687
type = type.getTop ();
1697
1688
}
1698
-
1689
+ assert (!type.isBasic () || exactness == Inexact);
1690
+ if (exactness == Exact) {
1691
+ o << uint8_t (BinaryConsts::EncodedType::Exact);
1692
+ }
1699
1693
if (!type.isBasic ()) {
1700
1694
o << S64LEB (getTypeIndex (type)); // TODO: Actually s33
1701
1695
return ;
@@ -2190,43 +2184,41 @@ Signature WasmBinaryReader::getBlockType() {
2190
2184
return Signature (Type::none, getType (code));
2191
2185
}
2192
2186
2193
- Type WasmBinaryReader::getTypeNoExact (int code) {
2187
+ Type WasmBinaryReader::getType (int code) {
2194
2188
Type type;
2195
2189
if (getBasicType (code, type)) {
2196
2190
return type;
2197
2191
}
2192
+ auto [heapType, exactness] = getHeapType ();
2198
2193
switch (code) {
2199
2194
case BinaryConsts::EncodedType::nullable:
2200
- return Type (getHeapType () , Nullable);
2195
+ return Type (heapType , Nullable, exactness );
2201
2196
case BinaryConsts::EncodedType::nonnullable:
2202
- return Type (getHeapType () , NonNullable);
2197
+ return Type (heapType , NonNullable, exactness );
2203
2198
default :
2204
2199
throwError (" invalid wasm type: " + std::to_string (code));
2205
2200
}
2206
2201
WASM_UNREACHABLE (" unexpected type" );
2207
2202
}
2208
2203
2209
- Type WasmBinaryReader::getType (int code) {
2210
- if (code == BinaryConsts::EncodedType::exact) {
2211
- auto type = getTypeNoExact (getS32LEB ());
2212
- if (!type.isRef ()) {
2213
- throwError (" invalid exact prefix on non-reference type" );
2214
- }
2215
- return Type (type.getHeapType (), type.getNullability (), Exact);
2216
- }
2217
- return getTypeNoExact (code);
2218
- }
2219
-
2220
2204
Type WasmBinaryReader::getType () { return getType (getS32LEB ()); }
2221
2205
2222
- HeapType WasmBinaryReader::getHeapType () {
2206
+ std::pair< HeapType, Exactness> WasmBinaryReader::getHeapType () {
2223
2207
auto type = getS64LEB (); // TODO: Actually s33
2208
+ auto exactness = Inexact;
2209
+ if (type == BinaryConsts::EncodedType::ExactLEB) {
2210
+ exactness = Exact;
2211
+ type = getS64LEB (); // TODO: Actually s33
2212
+ }
2224
2213
// Single heap types are negative; heap type indices are non-negative
2225
2214
if (type >= 0 ) {
2226
2215
if (size_t (type) >= types.size ()) {
2227
- throwError (" invalid signature index: " + std::to_string (type));
2216
+ throwError (" invalid type index: " + std::to_string (type));
2228
2217
}
2229
- return types[type];
2218
+ return {types[type], exactness};
2219
+ }
2220
+ if (exactness == Exact) {
2221
+ throwError (" invalid type index: " + std::to_string (type));
2230
2222
}
2231
2223
auto share = Unshared;
2232
2224
if (type == BinaryConsts::EncodedType::SharedLEB) {
@@ -2235,11 +2227,9 @@ HeapType WasmBinaryReader::getHeapType() {
2235
2227
}
2236
2228
HeapType ht;
2237
2229
if (getBasicHeapType (type, ht)) {
2238
- return ht.getBasic (share);
2239
- } else {
2240
- throwError (" invalid wasm heap type: " + std::to_string (type));
2230
+ return {ht.getBasic (share), Inexact};
2241
2231
}
2242
- WASM_UNREACHABLE ( " unexpected type" );
2232
+ throwError ( " invalid wasm heap type: " + std::to_string (type) );
2243
2233
}
2244
2234
2245
2235
HeapType WasmBinaryReader::getIndexedHeapType () {
@@ -2361,23 +2351,34 @@ void WasmBinaryReader::readMemories() {
2361
2351
void WasmBinaryReader::readTypes () {
2362
2352
TypeBuilder builder (getU32LEB ());
2363
2353
2364
- auto readHeapType = [&]() -> HeapType {
2354
+ auto readHeapType = [&]() -> std::pair< HeapType, Exactness> {
2365
2355
int64_t htCode = getS64LEB (); // TODO: Actually s33
2356
+ auto exactness = Inexact;
2357
+ if (htCode == BinaryConsts::EncodedType::ExactLEB) {
2358
+ exactness = Exact;
2359
+ htCode = getS64LEB (); // TODO: Actually s33
2360
+ }
2361
+ if (htCode >= 0 ) {
2362
+ if (size_t (htCode) >= builder.size ()) {
2363
+ throwError (" invalid type index: " + std::to_string (htCode));
2364
+ }
2365
+ return {builder.getTempHeapType (size_t (htCode)), exactness};
2366
+ }
2367
+ if (exactness == Exact) {
2368
+ throwError (" invalid type index: " + std::to_string (htCode));
2369
+ }
2366
2370
auto share = Unshared;
2367
2371
if (htCode == BinaryConsts::EncodedType::SharedLEB) {
2368
2372
share = Shared;
2369
2373
htCode = getS64LEB (); // TODO: Actually s33
2370
2374
}
2371
2375
HeapType ht;
2372
2376
if (getBasicHeapType (htCode, ht)) {
2373
- return ht.getBasic (share);
2374
- }
2375
- if (size_t (htCode) >= builder.size ()) {
2376
- throwError (" invalid type index: " + std::to_string (htCode));
2377
+ return {ht.getBasic (share), Inexact};
2377
2378
}
2378
- return builder. getTempHeapType ( size_t (htCode));
2379
+ throwError ( " invalid wasm heap type: " + std::to_string (htCode));
2379
2380
};
2380
- auto makeTypeNoExact = [&](int32_t typeCode) {
2381
+ auto makeType = [&](int32_t typeCode) {
2381
2382
Type type;
2382
2383
if (getBasicType (typeCode, type)) {
2383
2384
return type;
@@ -2390,29 +2391,18 @@ void WasmBinaryReader::readTypes() {
2390
2391
? Nullable
2391
2392
: NonNullable;
2392
2393
2393
- HeapType ht = readHeapType ();
2394
+ auto [ht, exactness] = readHeapType ();
2394
2395
if (ht.isBasic ()) {
2395
- return Type (ht, nullability);
2396
+ return Type (ht, nullability, exactness );
2396
2397
}
2397
2398
2398
- return builder.getTempRefType (ht, nullability);
2399
+ return builder.getTempRefType (ht, nullability, exactness );
2399
2400
}
2400
2401
default :
2401
2402
throwError (" unexpected type index: " + std::to_string (typeCode));
2402
2403
}
2403
2404
WASM_UNREACHABLE (" unexpected type" );
2404
2405
};
2405
- auto makeType = [&](int32_t typeCode) {
2406
- if (typeCode == BinaryConsts::EncodedType::exact) {
2407
- auto type = makeTypeNoExact (getS32LEB ());
2408
- if (!type.isRef ()) {
2409
- throwError (" unexpected exact prefix on non-reference type" );
2410
- }
2411
- return builder.getTempRefType (
2412
- type.getHeapType (), type.getNullability (), Exact);
2413
- }
2414
- return makeTypeNoExact (typeCode);
2415
- };
2416
2406
auto readType = [&]() { return makeType (getS32LEB ()); };
2417
2407
2418
2408
auto readSignatureDef = [&]() {
@@ -2431,7 +2421,10 @@ void WasmBinaryReader::readTypes() {
2431
2421
};
2432
2422
2433
2423
auto readContinuationDef = [&]() {
2434
- HeapType ht = readHeapType ();
2424
+ auto [ht, exactness] = readHeapType ();
2425
+ if (exactness != Inexact) {
2426
+ throw ParseException (" invalid exact type in cont definition" );
2427
+ }
2435
2428
if (!ht.isSignature ()) {
2436
2429
throw ParseException (" cont types must be built from function types" );
2437
2430
}
@@ -3046,8 +3039,12 @@ Result<> WasmBinaryReader::readInst() {
3046
3039
return builder.visitCatchAll ();
3047
3040
case BinaryConsts::Delegate:
3048
3041
return builder.visitDelegate (getU32LEB ());
3049
- case BinaryConsts::RefNull:
3050
- return builder.makeRefNull (getHeapType ());
3042
+ case BinaryConsts::RefNull: {
3043
+ auto [heapType, exactness] = getHeapType ();
3044
+ // Exactness is allowed but doesn't matter, since we always use the bottom
3045
+ // heap type.
3046
+ return builder.makeRefNull (heapType);
3047
+ }
3051
3048
case BinaryConsts::RefIsNull:
3052
3049
return builder.makeRefIsNull ();
3053
3050
case BinaryConsts::RefFunc:
@@ -4282,34 +4279,36 @@ Result<> WasmBinaryReader::readInst() {
4282
4279
return builder.makeI31Get (true );
4283
4280
case BinaryConsts::I31GetU:
4284
4281
return builder.makeI31Get (false );
4285
- case BinaryConsts::RefTest:
4286
- return builder.makeRefTest (Type (getHeapType (), NonNullable));
4287
- case BinaryConsts::RefTestNull:
4288
- return builder.makeRefTest (Type (getHeapType (), Nullable));
4289
- case BinaryConsts::RefTestRT:
4290
- return builder.makeRefTest (getType ());
4291
- case BinaryConsts::RefCast:
4292
- return builder.makeRefCast (Type (getHeapType (), NonNullable));
4293
- case BinaryConsts::RefCastNull:
4294
- return builder.makeRefCast (Type (getHeapType (), Nullable));
4295
- case BinaryConsts::RefCastRT:
4296
- return builder.makeRefCast (getType ());
4282
+ case BinaryConsts::RefTest: {
4283
+ auto [heapType, exactness] = getHeapType ();
4284
+ return builder.makeRefTest (Type (heapType, NonNullable, exactness));
4285
+ }
4286
+ case BinaryConsts::RefTestNull: {
4287
+ auto [heapType, exactness] = getHeapType ();
4288
+ return builder.makeRefTest (Type (heapType, Nullable, exactness));
4289
+ }
4290
+ case BinaryConsts::RefCast: {
4291
+ auto [heapType, exactness] = getHeapType ();
4292
+ return builder.makeRefCast (Type (heapType, NonNullable, exactness));
4293
+ }
4294
+ case BinaryConsts::RefCastNull: {
4295
+ auto [heapType, exactness] = getHeapType ();
4296
+ return builder.makeRefCast (Type (heapType, Nullable, exactness));
4297
+ }
4297
4298
case BinaryConsts::BrOnCast:
4298
4299
case BinaryConsts::BrOnCastFail: {
4299
4300
auto flags = getInt8 ();
4300
- auto label = getU32LEB ();
4301
4301
auto srcNull = (flags & BinaryConsts::BrOnCastFlag::InputNullable)
4302
4302
? Nullable
4303
4303
: NonNullable;
4304
4304
auto dstNull = (flags & BinaryConsts::BrOnCastFlag::OutputNullable)
4305
4305
? Nullable
4306
4306
: NonNullable;
4307
- auto srcExact =
4308
- (flags & BinaryConsts::BrOnCastFlag::InputExact) ? Exact : Inexact;
4309
- auto dstExact =
4310
- (flags & BinaryConsts::BrOnCastFlag::OutputExact) ? Exact : Inexact;
4311
- auto in = Type (getHeapType (), srcNull, srcExact);
4312
- auto cast = Type (getHeapType (), dstNull, dstExact);
4307
+ auto label = getU32LEB ();
4308
+ auto [srcType, srcExact] = getHeapType ();
4309
+ auto [dstType, dstExact] = getHeapType ();
4310
+ auto in = Type (srcType, srcNull, srcExact);
4311
+ auto cast = Type (dstType, dstNull, dstExact);
4313
4312
auto kind = op == BinaryConsts::BrOnCast ? BrOnCast : BrOnCastFail;
4314
4313
return builder.makeBrOn (label, kind, in, cast);
4315
4314
}
0 commit comments