diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 9ea8a7aa982..e61deed16aa 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -5761,7 +5761,7 @@ struct OptimizeInstructions } } - if (!neverFold) { + if (!neverFold && curr->condition->type != Type::unreachable) { // Identical code on both arms can be folded out, e.g. // // (select diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index b099926112c..64b67e51edd 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -4340,7 +4340,8 @@ void FunctionValidator::visitContNew(ContNew* curr) { auto cont = curr->type.getHeapType().getContinuation(); assert(cont.type.isSignature()); - shouldBeTrue(HeapType::isSubType(curr->func->type.getHeapType(), cont.type), + shouldBeTrue(curr->func->type.isRef() && + HeapType::isSubType(curr->func->type.getHeapType(), cont.type), curr, "cont.new function reference must be a subtype"); } diff --git a/test/gtest/validator.cpp b/test/gtest/validator.cpp index e984945226c..906e9369464 100644 --- a/test/gtest/validator.cpp +++ b/test/gtest/validator.cpp @@ -90,3 +90,28 @@ TEST(ValidatorTest, UnreachableCastDescEq) { WasmValidator::FlagValues::Globally | WasmValidator::FlagValues::Quiet; EXPECT_FALSE(WasmValidator{}.validate(func.get(), module, flags)); } + +TEST(ValidatorTest, ContNewUnreachable) { + Module module; + module.features = FeatureSet::All; + Builder builder(module); + + auto sig = Signature(Type::none, Type::none); + module.addFunction(builder.makeFunction( + "f", {}, Signature(Type::none, Type::none), {}, builder.makeUnreachable())); + + auto contType = HeapType(Continuation(sig)); + auto contRefType = Type(contType, NonNullable); + + // Create a cont.new with a concrete type despite an unreachable child. This + // is not valid, but we should not crash while validating it. + auto* contNew = builder.makeContNew(contType, builder.makeUnreachable()); + contNew->type = contRefType; + + auto testFunc = builder.makeFunction( + "test", {}, Signature(Type::none, contRefType), {}, contNew); + + auto flags = + WasmValidator::FlagValues::Globally | WasmValidator::FlagValues::Quiet; + EXPECT_FALSE(WasmValidator{}.validate(testFunc.get(), module, flags)); +} diff --git a/test/lit/passes/legalize-js-interface-exported-helpers.wast b/test/lit/passes/legalize-js-interface-exported-helpers.wast index bed768f1a0d..18b93cfc987 100644 --- a/test/lit/passes/legalize-js-interface-exported-helpers.wast +++ b/test/lit/passes/legalize-js-interface-exported-helpers.wast @@ -8,8 +8,6 @@ (module (export "get_i64" (func $get_i64)) (import "env" "imported" (func $imported (result i64))) - (export "__set_temp_ret" (func $__set_temp_ret)) - (export "__get_temp_ret" (func $__get_temp_ret)) ;; CHECK: (type $0 (func (result i32))) ;; CHECK: (type $1 (func (result i64))) @@ -20,6 +18,10 @@ ;; CHECK: (export "get_i64" (func $legalstub$get_i64)) + ;; CHECK: (export "__set_temp_ret" (func $__set_temp_ret)) + (export "__set_temp_ret" (func $__set_temp_ret)) + ;; CHECK: (export "__get_temp_ret" (func $__get_temp_ret)) + (export "__get_temp_ret" (func $__get_temp_ret)) ;; CHECK: (func $get_i64 (result i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $legalfunc$imported) diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index 9dc52715724..c8532cf7ae4 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -3695,13 +3695,15 @@ ;; CHECK: (func $comp-i31-struct-unreachable-if (type $4) ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.i31 - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (if (result (ref i31)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (ref.i31 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (ref.i31 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/optimize-instructions-mvp.wast b/test/lit/passes/optimize-instructions-mvp.wast index a301cc6858c..021b868bcc1 100644 --- a/test/lit/passes/optimize-instructions-mvp.wast +++ b/test/lit/passes/optimize-instructions-mvp.wast @@ -16046,6 +16046,37 @@ ) ) ) + ;; CHECK: (func $ternary-identical-arms-if-unreachable (param $x i32) (param $y i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (if (result i32) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (i32.eqz + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $ternary-identical-arms-if-unreachable (param $x i32) (param $y i32) + (drop + ;; Leave this to DCE instead of optimizing. + (if (result i32) + (unreachable) + (then + (i32.eqz (local.get $x)) + ) + (else + (i32.eqz (local.get $y)) + ) + ) + ) + ) ;; CHECK: (func $ternary-identical-arms-type-change (param $x f64) (param $y f64) (param $z i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (f32.demote_f64