From cad723a3827913f53ecfa7189b011be389d28ae7 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 17 Dec 2020 16:47:38 -0800 Subject: [GC] Add br_on_cast (#3451) The tricky part here, as pointed out by aheejin in my previous attempt, is that we need to know the type of the value we send if the branch is taken. We can normally calculate that from the rtt parameter's type - we are casting to that RTT, so we know what type that is - but if the rtt is unreachable, that's a problem. To fix that, store the cast type on BrOnCast instructions. This includes a test with a br_on_cast that succeeds and sends the cast value, one that fails and passes through the uncast value, and also of one with an unreachable RTT. This includes a fix for Precompute, as noticed by that new test. If a break is taken, with a ref as a value, we can't precompute it - for the same reasons we can't precompute a ref in general, that it is a pointer to possibly shared data. --- src/wasm/wasm-validator.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src/wasm/wasm-validator.cpp') diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index f110faf56..edcf3676d 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2214,11 +2214,11 @@ void FunctionValidator::visitRefCast(RefCast* curr) { getModule()->features.hasGC(), curr, "ref.cast requires gc to be enabled"); if (curr->ref->type != Type::unreachable) { shouldBeTrue( - curr->ref->type.isRef(), curr, "ref.test ref must have ref type"); + curr->ref->type.isRef(), curr, "ref.cast ref must have ref type"); } if (curr->rtt->type != Type::unreachable) { shouldBeTrue( - curr->rtt->type.isRtt(), curr, "ref.test rtt must have rtt type"); + curr->rtt->type.isRtt(), curr, "ref.cast rtt must have rtt type"); } } @@ -2226,7 +2226,19 @@ void FunctionValidator::visitBrOnCast(BrOnCast* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, "br_on_cast requires gc to be enabled"); - WASM_UNREACHABLE("TODO (gc): br_on_cast"); + if (curr->ref->type != Type::unreachable) { + shouldBeTrue( + curr->ref->type.isRef(), curr, "br_on_cast ref must have ref type"); + } + if (curr->rtt->type != Type::unreachable) { + shouldBeTrue( + curr->rtt->type.isRtt(), curr, "br_on_cast rtt must have rtt type"); + shouldBeEqual(curr->rtt->type.getHeapType(), + curr->castType.getHeapType(), + curr, + "br_on_cast rtt must have the proper heap type"); + noteBreak(curr->name, Type(curr->rtt->type.getHeapType(), Nullable), curr); + } } void FunctionValidator::visitRttCanon(RttCanon* curr) { @@ -2368,15 +2380,15 @@ void FunctionValidator::visitArrayGet(ArrayGet* curr) { getModule()->features.hasGC(), curr, "array.get requires gc to be enabled"); shouldBeEqualOrFirstIsUnreachable( curr->index->type, Type(Type::i32), curr, "array.get index must be an i32"); + if (curr->type == Type::unreachable) { + return; + } const auto& element = curr->ref->type.getHeapType().getArray().element; // If the type is not packed, it must be marked internally as unsigned, by // convention. if (element.type != Type::i32 || element.packedType == Field::not_packed) { shouldBeFalse(curr->signed_, curr, "non-packed get cannot be signed"); } - if (curr->type == Type::unreachable) { - return; - } shouldBeEqual( curr->type, element.type, curr, "array.get must have the proper type"); } -- cgit v1.2.3