Skip to content

Commit fbf2010

Browse files
authored
Revert exact reference types (#7402)
We decided that Custom Descriptors should introduce exact heap types rather than exact reference types. Although these new features are very similar, the APIs we need to change for them are completely different. One option would have been to keep the existing exact reference type implementation while additionally implementing exact heap types, but there are not enough free bits in the type implementation to have both at once without increasing the alignment of HeapTypeInfo allocations. Portably increasing the alignment is annoying enough that it's easier to just eagerly remove exact reference types to free up the bit for use with exact heap types. Fully or partially revert the following PRs: - #7371 - #7365 - #7360 - #7357 - #7356 - #7355 - #7354 - #7353 - #7347 - #7342 - #7328 Keep the new `.with(...)` Type APIs and the relevant parts of the type relations gtest that were introduced as part of the reverted work.
1 parent 0997f9b commit fbf2010

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+337
-1647
lines changed

scripts/test/fuzzing.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,6 @@
104104
'stack_switching_resume.wast',
105105
'stack_switching_resume_throw.wast',
106106
'stack_switching_switch.wast',
107-
# TODO: fuzzer support for exact references
108-
'exact-references.wast',
109-
'optimize-instructions-exact.wast',
110-
'local-subtyping-exact.wast',
111-
'remove-unused-types-exact.wast',
112-
'coalesce-locals-exact.wast',
113-
'remove-unused-brs-exact.wast',
114-
'exact.wast',
115107
# TODO: fuzzer support for custom descriptors
116108
'custom-descriptors.wast',
117109
]

src/ir/manipulation.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ template<typename InputType> inline Nop* nop(InputType* target) {
4040
}
4141

4242
template<typename InputType>
43-
inline RefNull* refNull(InputType* target, HeapType type) {
43+
inline RefNull* refNull(InputType* target, Type type) {
44+
assert(type.isNullable() && type.getHeapType().isBottom());
4445
auto* ret = convert<InputType, RefNull>(target);
45-
ret->finalize(Type(type.getBottom(), Nullable, Exact));
46+
ret->finalize(type);
4647
return ret;
4748
}
4849

src/ir/type-updating.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ Type GlobalTypeRewriter::getTempType(Type type) {
342342
if (type.isRef()) {
343343
auto heapType = type.getHeapType();
344344
if (auto it = typeIndices.find(heapType); it != typeIndices.end()) {
345-
// TODO: Handle exactness.
346345
return typeBuilder.getTempRefType(typeBuilder[it->second],
347346
type.getNullability());
348347
}

src/ir/type-updating.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,6 @@ class TypeMapper : public GlobalTypeRewriter {
497497
auto heapType = type.getHeapType();
498498
auto iter = mapping.find(heapType);
499499
if (iter != mapping.end()) {
500-
// TODO: Handle exactness.
501500
return getTempType(Type(iter->second, type.getNullability()));
502501
}
503502
return getTempType(type);

src/literal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class Literal {
246246
}
247247
}
248248
static Literal makeNull(HeapType type) {
249-
return Literal(Type(type.getBottom(), Nullable, Exact));
249+
return Literal(Type(type.getBottom(), Nullable));
250250
}
251251
static Literal makeFunc(Name func, HeapType type) {
252252
return Literal(func, type);

src/parser/contexts.h

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ struct NullTypeParserCtx {
127127
TypeT makeF64() { return Ok{}; }
128128
TypeT makeV128() { return Ok{}; }
129129

130-
TypeT makeRefType(HeapTypeT, Nullability, Exactness) { return Ok{}; }
131-
132-
HeapTypeT getHeapTypeFromRefType(TypeT) { return Ok{}; }
130+
TypeT makeRefType(HeapTypeT, Nullability) { return Ok{}; }
133131

134132
TupleElemListT makeTupleElemList() { return Ok{}; }
135133
void appendTupleElem(TupleElemListT&, TypeT) {}
@@ -259,13 +257,10 @@ template<typename Ctx> struct TypeParserCtx {
259257
TypeT makeF64() { return Type::f64; }
260258
TypeT makeV128() { return Type::v128; }
261259

262-
TypeT
263-
makeRefType(HeapTypeT ht, Nullability nullability, Exactness exactness) {
264-
return Type(ht, nullability, exactness);
260+
TypeT makeRefType(HeapTypeT ht, Nullability nullability) {
261+
return Type(ht, nullability);
265262
}
266263

267-
HeapTypeT getHeapTypeFromRefType(TypeT t) { return t.getHeapType(); }
268-
269264
std::vector<Type> makeTupleElemList() { return {}; }
270265
void appendTupleElem(std::vector<Type>& elems, Type elem) {
271266
elems.push_back(elem);
@@ -1122,13 +1117,10 @@ struct ParseTypeDefsCtx : TypeParserCtx<ParseTypeDefsCtx> {
11221117
: TypeParserCtx<ParseTypeDefsCtx>(typeIndices), in(in), builder(builder),
11231118
names(builder.size()) {}
11241119

1125-
TypeT
1126-
makeRefType(HeapTypeT ht, Nullability nullability, Exactness exactness) {
1127-
return builder.getTempRefType(ht, nullability, exactness);
1120+
TypeT makeRefType(HeapTypeT ht, Nullability nullability) {
1121+
return builder.getTempRefType(ht, nullability);
11281122
}
11291123

1130-
HeapTypeT getHeapTypeFromRefType(TypeT t) { return t.getHeapType(); }
1131-
11321124
TypeT makeTupleType(const std::vector<Type> types) {
11331125
return builder.getTempTupleType(types);
11341126
}

src/parser/parsers.h

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ using namespace std::string_view_literals;
3030
template<typename Ctx>
3131
Result<typename Ctx::HeapTypeT> absheaptype(Ctx&, Shareability);
3232
template<typename Ctx> Result<typename Ctx::HeapTypeT> heaptype(Ctx&);
33-
template<typename Ctx>
34-
MaybeResult<typename Ctx::TypeT> maybeReftypeAbbrev(Ctx&);
3533
template<typename Ctx> MaybeResult<typename Ctx::RefTypeT> maybeReftype(Ctx&);
3634
template<typename Ctx> Result<typename Ctx::RefTypeT> reftype(Ctx&);
3735
template<typename Ctx> MaybeResult<typename Ctx::TypeT> tupletype(Ctx&);
@@ -460,85 +458,68 @@ template<typename Ctx> Result<typename Ctx::HeapTypeT> heaptype(Ctx& ctx) {
460458
// | 'i31ref' => i31ref
461459
// | 'structref' => structref
462460
// | 'arrayref' => arrayref
463-
// | ...
464-
template<typename Ctx>
465-
MaybeResult<typename Ctx::TypeT> maybeReftypeAbbrev(Ctx& ctx) {
461+
// | '(' ref null? t:heaptype ')' => ref null? t
462+
template<typename Ctx> MaybeResult<typename Ctx::TypeT> maybeReftype(Ctx& ctx) {
466463
if (ctx.in.takeKeyword("funcref"sv)) {
467-
return ctx.makeRefType(ctx.makeFuncType(Unshared), Nullable, Inexact);
464+
return ctx.makeRefType(ctx.makeFuncType(Unshared), Nullable);
468465
}
469466
if (ctx.in.takeKeyword("externref"sv)) {
470-
return ctx.makeRefType(ctx.makeExternType(Unshared), Nullable, Inexact);
467+
return ctx.makeRefType(ctx.makeExternType(Unshared), Nullable);
471468
}
472469
if (ctx.in.takeKeyword("anyref"sv)) {
473-
return ctx.makeRefType(ctx.makeAnyType(Unshared), Nullable, Inexact);
470+
return ctx.makeRefType(ctx.makeAnyType(Unshared), Nullable);
474471
}
475472
if (ctx.in.takeKeyword("eqref"sv)) {
476-
return ctx.makeRefType(ctx.makeEqType(Unshared), Nullable, Inexact);
473+
return ctx.makeRefType(ctx.makeEqType(Unshared), Nullable);
477474
}
478475
if (ctx.in.takeKeyword("i31ref"sv)) {
479-
return ctx.makeRefType(ctx.makeI31Type(Unshared), Nullable, Inexact);
476+
return ctx.makeRefType(ctx.makeI31Type(Unshared), Nullable);
480477
}
481478
if (ctx.in.takeKeyword("structref"sv)) {
482-
return ctx.makeRefType(ctx.makeStructType(Unshared), Nullable, Inexact);
479+
return ctx.makeRefType(ctx.makeStructType(Unshared), Nullable);
483480
}
484481
if (ctx.in.takeKeyword("arrayref"sv)) {
485-
return ctx.makeRefType(ctx.makeArrayType(Unshared), Nullable, Inexact);
482+
return ctx.makeRefType(ctx.makeArrayType(Unshared), Nullable);
486483
}
487484
if (ctx.in.takeKeyword("exnref"sv)) {
488-
return ctx.makeRefType(ctx.makeExnType(Unshared), Nullable, Inexact);
485+
return ctx.makeRefType(ctx.makeExnType(Unshared), Nullable);
489486
}
490487
if (ctx.in.takeKeyword("stringref"sv)) {
491-
return ctx.makeRefType(ctx.makeStringType(Unshared), Nullable, Inexact);
488+
return ctx.makeRefType(ctx.makeStringType(Unshared), Nullable);
492489
}
493490
if (ctx.in.takeKeyword("contref"sv)) {
494-
return ctx.makeRefType(ctx.makeContType(Unshared), Nullable, Inexact);
491+
return ctx.makeRefType(ctx.makeContType(Unshared), Nullable);
495492
}
496493
if (ctx.in.takeKeyword("nullref"sv)) {
497-
return ctx.makeRefType(ctx.makeNoneType(Unshared), Nullable, Inexact);
494+
return ctx.makeRefType(ctx.makeNoneType(Unshared), Nullable);
498495
}
499496
if (ctx.in.takeKeyword("nullexternref"sv)) {
500-
return ctx.makeRefType(ctx.makeNoextType(Unshared), Nullable, Inexact);
497+
return ctx.makeRefType(ctx.makeNoextType(Unshared), Nullable);
501498
}
502499
if (ctx.in.takeKeyword("nullfuncref"sv)) {
503-
return ctx.makeRefType(ctx.makeNofuncType(Unshared), Nullable, Inexact);
500+
return ctx.makeRefType(ctx.makeNofuncType(Unshared), Nullable);
504501
}
505502
if (ctx.in.takeKeyword("nullexnref"sv)) {
506-
return ctx.makeRefType(ctx.makeNoexnType(Unshared), Nullable, Inexact);
503+
return ctx.makeRefType(ctx.makeNoexnType(Unshared), Nullable);
507504
}
508505
if (ctx.in.takeKeyword("nullcontref"sv)) {
509-
return ctx.makeRefType(ctx.makeNocontType(Unshared), Nullable, Inexact);
506+
return ctx.makeRefType(ctx.makeNocontType(Unshared), Nullable);
510507
}
511-
return {};
512-
}
513508

514-
// reftype ::= ...
515-
// | '(' 'exact' (ref null ht):shorthand ')' => ref null exact ht
516-
// | '(' ref null? exact? ht:heaptype ')' => ref null? t
517-
template<typename Ctx> MaybeResult<typename Ctx::TypeT> maybeReftype(Ctx& ctx) {
518-
if (ctx.in.takeSExprStart("exact"sv)) {
519-
auto rt = maybeReftypeAbbrev(ctx);
520-
CHECK_ERR(rt);
521-
if (!rt) {
522-
return ctx.in.err("expected reftype shorthand");
523-
}
524-
if (!ctx.in.takeRParen()) {
525-
return ctx.in.err("expected end of reftype");
526-
}
527-
return ctx.makeRefType(ctx.getHeapTypeFromRefType(*rt), Nullable, Exact);
509+
if (!ctx.in.takeSExprStart("ref"sv)) {
510+
return {};
528511
}
529512

530-
if (ctx.in.takeSExprStart("ref"sv)) {
531-
auto nullability = ctx.in.takeKeyword("null"sv) ? Nullable : NonNullable;
532-
auto exactness = ctx.in.takeKeyword("exact"sv) ? Exact : Inexact;
533-
auto type = heaptype(ctx);
534-
CHECK_ERR(type);
535-
if (!ctx.in.takeRParen()) {
536-
return ctx.in.err("expected end of reftype");
537-
}
538-
return ctx.makeRefType(*type, nullability, exactness);
513+
auto nullability = ctx.in.takeKeyword("null"sv) ? Nullable : NonNullable;
514+
515+
auto type = heaptype(ctx);
516+
CHECK_ERR(type);
517+
518+
if (!ctx.in.takeRParen()) {
519+
return ctx.in.err("expected end of reftype");
539520
}
540521

541-
return maybeReftypeAbbrev(ctx);
522+
return ctx.makeRefType(*type, nullability);
542523
}
543524

544525
template<typename Ctx> Result<typename Ctx::TypeT> reftype(Ctx& ctx) {

src/passes/OptimizeInstructions.cpp

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,14 +2277,10 @@ struct OptimizeInstructions
22772277
// emit a null check.
22782278
bool needsNullCheck = ref->type.getNullability() == Nullable &&
22792279
curr->type.getNullability() == NonNullable;
2280-
// Same with exactness.
2281-
bool needsExactCast = ref->type.getExactness() == Inexact &&
2282-
curr->type.getExactness() == Exact;
22832280
// If the best value to propagate is the argument to the cast, we can
22842281
// simply remove the cast (or downgrade it to a null check if
2285-
// necessary). This does not work if we need a cast to prove
2286-
// exactness.
2287-
if (ref == curr->ref && !needsExactCast) {
2282+
// necessary).
2283+
if (ref == curr->ref) {
22882284
if (needsNullCheck) {
22892285
replaceCurrent(builder.makeRefAs(RefAsNonNull, curr->ref));
22902286
} else {
@@ -2293,17 +2289,17 @@ struct OptimizeInstructions
22932289
return;
22942290
}
22952291
// Otherwise we can't just remove the cast and replace it with `ref`
2296-
// because the intermediate expressions might have had side effects or
2297-
// we need to check exactness. We can replace the cast with a drop
2298-
// followed by a direct return of the value, though.
2292+
// because the intermediate expressions might have had side effects.
2293+
// We can replace the cast with a drop followed by a direct return of
2294+
// the value, though.
22992295
if (ref->type.isNull()) {
23002296
// We can materialize the resulting null value directly.
23012297
//
23022298
// The type must be nullable for us to do that, which it normally
23032299
// would be, aside from the interesting corner case of
23042300
// uninhabitable types:
23052301
//
2306-
// (ref.cast (ref func)
2302+
// (ref.cast func
23072303
// (block (result (ref nofunc))
23082304
// (unreachable)
23092305
// )
@@ -2350,20 +2346,18 @@ struct OptimizeInstructions
23502346
}
23512347
[[fallthrough]];
23522348
case GCTypeUtils::SuccessOnlyIfNull: {
2349+
auto nullType = Type(curr->type.getHeapType().getBottom(), Nullable);
23532350
// The cast either returns null or traps. In trapsNeverHappen mode
23542351
// we know the result, since by assumption it will not trap.
23552352
if (getPassOptions().trapsNeverHappen) {
2356-
replaceCurrent(
2357-
builder.makeBlock({builder.makeDrop(curr->ref),
2358-
builder.makeRefNull(curr->type.getHeapType())},
2359-
curr->type));
2353+
replaceCurrent(builder.makeBlock(
2354+
{builder.makeDrop(curr->ref), builder.makeRefNull(nullType)},
2355+
curr->type));
23602356
return;
23612357
}
23622358
// Otherwise, we should have already refined the cast type to cast
2363-
// directly to null. We do not further refine the cast type to exact
2364-
// null because the extra precision is not useful and doing so would
2365-
// increase the size of the instruction encoding.
2366-
assert(curr->type.isNull());
2359+
// directly to null.
2360+
assert(curr->type == nullType);
23672361
break;
23682362
}
23692363
case GCTypeUtils::Unreachable:

src/passes/RemoveUnusedBrs.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,8 +859,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
859859
if (Type::isSubType(expr->type, type)) {
860860
return expr;
861861
}
862-
if (type.isNonNullable() && expr->type.isNullable() &&
863-
Type::isSubType(expr->type.with(NonNullable), type)) {
862+
if (HeapType::isSubType(expr->type.getHeapType(),
863+
type.getHeapType())) {
864864
return builder.makeRefAs(RefAsNonNull, expr);
865865
}
866866
return builder.makeRefCast(expr, type);

src/tools/fuzzing.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,6 @@ class TranslateToFuzzReader {
360360
// instruction for EH is supposed to exist only at the beginning of a 'catch'
361361
// block, so it shouldn't be moved around or deleted freely.
362362
bool canBeArbitrarilyReplaced(Expression* curr) {
363-
// TODO: Remove this once we better support exact references.
364-
if (curr->type.isExact()) {
365-
return false;
366-
}
367363
return curr->type.isDefaultable() &&
368364
!EHUtils::containsValidDanglingPop(curr);
369365
}
@@ -525,9 +521,7 @@ class TranslateToFuzzReader {
525521
Type getLoggableType();
526522
bool isLoggableType(Type type);
527523
Nullability getNullability();
528-
Exactness getExactness();
529524
Nullability getSubType(Nullability nullability);
530-
Exactness getSubType(Exactness exactness);
531525
HeapType getSubType(HeapType type);
532526
Type getSubType(Type type);
533527
Nullability getSuperType(Nullability nullability);

0 commit comments

Comments
 (0)