From f6efc554dbb0a761c1db23a55ed724ffb49e0a4a Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 24 Sep 2026 11:17:52 -0700 Subject: [PATCH] [MakeSharedObjects] Add a pass arg to leave types unshared This will allow us to separate the slowdown from using the shared heap from the slowdown due to all the other transformations we have to apply. --- src/passes/MakeSharedObjects.cpp | 51 +- .../passes/make-shared-objects-unshared.wast | 530 ++++++++++++++++++ 2 files changed, 563 insertions(+), 18 deletions(-) create mode 100644 test/lit/passes/make-shared-objects-unshared.wast diff --git a/src/passes/MakeSharedObjects.cpp b/src/passes/MakeSharedObjects.cpp index 044e44f5031..6149869583c 100644 --- a/src/passes/MakeSharedObjects.cpp +++ b/src/passes/MakeSharedObjects.cpp @@ -113,6 +113,13 @@ struct LazyTable { return indexToRefName; } + // In normal operation, we are making types in the any hierarchy shared, but + // with pass arg 'make-shared-objects-unshared', we overwrite this to make + // them unshared instead. That helps separate the performance difference from + // using the shared heap from the performance difference due to other + // transformations we do in this pass. + Shareability shared = Shared; + void addRefToIndexFunction() { // (func $_to_index (param $ref ) (result (ref null (shared i31))) // (local $idx i32) @@ -141,10 +148,10 @@ struct LazyTable { // ) Builder builder(*wasm); - Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(Shared), Nullable); - Type sharedI31NonNull = Type(HeapTypes::i31.getBasic(Shared), NonNullable); + Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(shared), Nullable); + Type sharedI31NonNull = Type(HeapTypes::i31.getBasic(shared), NonNullable); auto* isNull = builder.makeRefIsNull(builder.makeLocalGet(0, type)); - auto* retNull = builder.makeRefNull(HeapTypes::none.getBasic(Shared)); + auto* retNull = builder.makeRefNull(HeapTypes::none.getBasic(shared)); auto* grow = builder.makeTableGrow(getName(), builder.makeLocalGet(0, type), builder.makeConst(Literal(int32_t(1)))); @@ -152,7 +159,7 @@ struct LazyTable { auto* geZero = builder.makeBinary(GeSInt32, tee, builder.makeConst(Literal(int32_t(0)))); auto* retIndex = - builder.makeRefI31(builder.makeLocalGet(1, Type::i32), Shared); + builder.makeRefI31(builder.makeLocalGet(1, Type::i32), shared); auto* checkGrow = builder.makeIf( geZero, retIndex, builder.makeUnreachable(), sharedI31NonNull); @@ -177,7 +184,7 @@ struct LazyTable { // ) Builder builder(*wasm); - Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(Shared), Nullable); + Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(shared), Nullable); auto* isNull = builder.makeRefIsNull(builder.makeLocalGet(0, sharedI31Nullable)); auto* retNull = builder.makeRefNull(type.getHeapType().getBottom()); @@ -259,7 +266,7 @@ struct LazyTable { return arg; } Builder builder(*wasm); - Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(Shared), Nullable); + Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(shared), Nullable); Expression* res = builder.makeCall(getRefToIndexName(), {arg}, sharedI31Nullable); if (targetType.isNonNullable()) { @@ -272,6 +279,7 @@ struct LazyTable { struct MakeSharedObjects : WalkerPass>> { + Shareability shared = Shared; Type funcref = Type(HeapTypes::func, Nullable); Type externref = Type(HeapTypes::ext, Nullable); @@ -315,19 +323,19 @@ struct MakeSharedObjects HeapType updatedHeapType(HeapType type) { if (type.isMaybeShared(HeapType::func) || type.isSignature()) { - return HeapTypes::i31.getBasic(Shared); + return HeapTypes::i31.getBasic(shared); } if (type.isMaybeShared(HeapType::nofunc)) { - return HeapTypes::none.getBasic(Shared); + return HeapTypes::none.getBasic(shared); } if (type == HeapType::ext || type == HeapType::string) { - return HeapTypes::i31.getBasic(Shared); + return HeapTypes::i31.getBasic(shared); } if (type == HeapType::noext) { - return HeapTypes::none.getBasic(Shared); + return HeapTypes::none.getBasic(shared); } if (type.isBasic()) { - return type.getBasic(Shared); + return type.getBasic(shared); } return type; } @@ -507,7 +515,7 @@ struct MakeSharedObjects void visitRefFunc(RefFunc* curr) { Builder builder(*getModule()); replaceCurrent( - builder.makeRefI31(builder.makeConst(Literal(getIndex(curr))), Shared)); + builder.makeRefI31(builder.makeConst(Literal(getIndex(curr))), shared)); } std::unordered_map callRefTypes; @@ -702,7 +710,7 @@ struct MakeSharedObjects Type extType = Type(HeapTypes::ext, curr->type.getNullability()); Expression* ext = externTable.convertToRef(curr->value, extType); Builder builder(*getModule()); - Type sharedAnyNullable = Type(HeapTypes::any.getBasic(Shared), Nullable); + Type sharedAnyNullable = Type(HeapTypes::any.getBasic(shared), Nullable); Expression* call = builder.makeCall(getExternToAnyName(), {ext}, sharedAnyNullable); if (curr->type.isNonNullable()) { @@ -824,7 +832,7 @@ struct MakeSharedObjects global->module = Name(); global->base = Name(); global->init = - builder.makeRefI31(builder.makeConst(Literal(int32_t(index))), Shared); + builder.makeRefI31(builder.makeConst(Literal(int32_t(index))), shared); getModule()->addGlobal(std::move(importGlobal)); } @@ -843,9 +851,16 @@ struct MakeSharedObjects } void doWalkModule(Module* wasm) { + if (hasArgument("make-shared-objects-unshared")) { + shared = Unshared; + } funcTable.wasm = wasm; + funcTable.shared = shared; externTable.wasm = wasm; - wasm->features.setSharedEverything(); + externTable.shared = shared; + if (shared == Shared) { + wasm->features.setSharedEverything(); + } WalkerPass::doWalkModule(wasm); } @@ -946,7 +961,7 @@ struct MakeSharedObjects builder[i].subTypeOf(builder[info.indices.at(*super)]); } } else { - builder[i].setShared(Shared); + builder[i].setShared(shared); } } @@ -967,7 +982,7 @@ struct MakeSharedObjects } void addAnyToExternFunction() { - Type sharedAnyNullable = Type(HeapTypes::any.getBasic(Shared), Nullable); + Type sharedAnyNullable = Type(HeapTypes::any.getBasic(shared), Nullable); Type externrefNullable = Type(HeapTypes::ext, Nullable); auto importFunc = Builder::makeFunction( anyToExternName, Signature(sharedAnyNullable, externrefNullable), {}); @@ -979,7 +994,7 @@ struct MakeSharedObjects void addExternToAnyFunction() { Type externrefNullable = Type(HeapTypes::ext, Nullable); - Type sharedAnyNullable = Type(HeapTypes::any.getBasic(Shared), Nullable); + Type sharedAnyNullable = Type(HeapTypes::any.getBasic(shared), Nullable); auto importFunc = Builder::makeFunction( externToAnyName, Signature(externrefNullable, sharedAnyNullable), {}); importFunc->module = "env"; diff --git a/test/lit/passes/make-shared-objects-unshared.wast b/test/lit/passes/make-shared-objects-unshared.wast new file mode 100644 index 00000000000..16b5d728568 --- /dev/null +++ b/test/lit/passes/make-shared-objects-unshared.wast @@ -0,0 +1,530 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: wasm-opt %s -all --make-shared-objects -S -o - | filecheck %s --check-prefix=SHARED +;; RUN: wasm-opt %s -all --make-shared-objects --pass-arg=make-shared-objects-unshared -S -o - | filecheck %s --check-prefix=UNSHARED + +(module + ;; SHARED: (type $struct (shared (struct (field (mut (ref null (shared i31)))) (field (mut (ref null (shared i31)))) (field (mut (ref null (shared any))))))) + + ;; SHARED: (type $sig (func (param (ref null (shared i31)) (ref null (shared i31))) (result (ref null (shared any))))) + ;; UNSHARED: (type $struct (struct (field (mut i31ref)) (field (mut i31ref)) (field (mut anyref)))) + + ;; UNSHARED: (type $sig (func (param i31ref i31ref) (result anyref))) + (type $sig (func (param funcref externref) (result anyref))) + (type $struct (struct (field (mut funcref)) (field (mut externref)) (field (mut anyref)))) + ;; SHARED: (type $array (shared (array (mut (ref null $struct))))) + ;; UNSHARED: (type $array (array (mut (ref null $struct)))) + (type $array (array (mut (ref null $struct)))) + + (import "env" "imported_func" (func $imported_func (param funcref externref) (result funcref externref))) + (import "env" "imported_global" (global $imported_global externref)) + ;; SHARED: (type $3 (func (param externref))) + + ;; SHARED: (type $4 (func (param (ref null (shared i31)) (ref null (shared i31))) (result (ref null (shared i31)) (ref null (shared i31))))) + + ;; SHARED: (type $5 (func (param (ref null $array)))) + + ;; SHARED: (type $6 (func (param (ref $struct)))) + + ;; SHARED: (type $7 (func (param (ref $struct) (ref (shared i31))))) + + ;; SHARED: (type $8 (func (param (ref $struct)) (result (ref null (shared i31))))) + + ;; SHARED: (type $9 (func (param (ref null (shared i31))) (result (ref null (shared i31))))) + + ;; SHARED: (type $10 (func (param (ref null (shared i31)) externref) (result (ref null (shared i31)) externref))) + + ;; SHARED: (type $11 (func (param (ref null (shared i31)) externref) (result (ref null (shared any))))) + + ;; SHARED: (type $12 (func (param externref) (result (ref null (shared i31))))) + + ;; SHARED: (type $13 (func (param (ref null (shared i31))) (result externref))) + + ;; SHARED: (type $14 (func (param (ref null (shared any))) (result externref))) + + ;; SHARED: (type $15 (func (param externref) (result (ref null (shared any))))) + + ;; SHARED: (type $16 (func (result (ref null (shared i31)) (ref null (shared i31))))) + + ;; SHARED: (import "env" "imported_global" (global $imported_global$import externref)) + + ;; SHARED: (import "env" "imported_func" (func $imported_func$import (type $10) (param (ref null (shared i31)) externref) (result (ref null (shared i31)) externref))) + + ;; SHARED: (import "env" "any_to_extern" (func $any_to_extern (exact (type $14) (param (ref null (shared any))) (result externref)))) + + ;; SHARED: (import "env" "extern_to_any" (func $extern_to_any (exact (type $15) (param externref) (result (ref null (shared any)))))) + + ;; SHARED: (import "env" "tag" (tag $tag (type $3) (param externref))) + ;; UNSHARED: (type $3 (func (param externref))) + + ;; UNSHARED: (type $4 (func (param i31ref i31ref) (result i31ref i31ref))) + + ;; UNSHARED: (type $5 (func (param (ref null $array)))) + + ;; UNSHARED: (type $6 (func (param (ref $struct)))) + + ;; UNSHARED: (type $7 (func (param (ref $struct) (ref i31)))) + + ;; UNSHARED: (type $8 (func (param (ref $struct)) (result i31ref))) + + ;; UNSHARED: (type $9 (func (param i31ref) (result i31ref))) + + ;; UNSHARED: (type $10 (func (param i31ref externref) (result i31ref externref))) + + ;; UNSHARED: (type $11 (func (param i31ref externref) (result anyref))) + + ;; UNSHARED: (type $12 (func (param externref) (result i31ref))) + + ;; UNSHARED: (type $13 (func (param i31ref) (result externref))) + + ;; UNSHARED: (type $14 (func (param anyref) (result externref))) + + ;; UNSHARED: (type $15 (func (param externref) (result anyref))) + + ;; UNSHARED: (type $16 (func (result i31ref i31ref))) + + ;; UNSHARED: (import "env" "imported_global" (global $imported_global$import externref)) + + ;; UNSHARED: (import "env" "imported_func" (func $imported_func$import (type $10) (param i31ref externref) (result i31ref externref))) + + ;; UNSHARED: (import "env" "any_to_extern" (func $any_to_extern (exact (type $14) (param anyref) (result externref)))) + + ;; UNSHARED: (import "env" "extern_to_any" (func $extern_to_any (exact (type $15) (param externref) (result anyref)))) + + ;; UNSHARED: (import "env" "tag" (tag $tag (type $3) (param externref))) + (import "env" "tag" (tag $tag (param externref))) + + (export "exported_func" (func $exported_func)) + + ;; SHARED: (global $imported_global (ref null (shared i31)) (ref.i31_shared + ;; SHARED-NEXT: (i32.const 0) + ;; SHARED-NEXT: )) + + ;; SHARED: (table $funcs 1 1 funcref) + + ;; SHARED: (table $externs 1 externref) + + ;; SHARED: (elem $funcs (table $funcs) (i32.const 0) func $exported_func) + + ;; SHARED: (elem $externs (table $externs) (i32.const 0) externref (item (global.get $imported_global$import))) + + ;; SHARED: (export "exported_func" (func $exported_func$export)) + + ;; SHARED: (func $imported_func (type $4) (param $0 (ref null (shared i31))) (param $1 (ref null (shared i31))) (result (ref null (shared i31)) (ref null (shared i31))) + ;; SHARED-NEXT: (local $2 (tuple (ref null (shared i31)) externref)) + ;; SHARED-NEXT: (local.set $2 + ;; SHARED-NEXT: (call $imported_func$import + ;; SHARED-NEXT: (local.get $0) + ;; SHARED-NEXT: (call $index_to_extern + ;; SHARED-NEXT: (local.get $1) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (tuple.make 2 + ;; SHARED-NEXT: (tuple.extract 2 0 + ;; SHARED-NEXT: (local.get $2) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (call $extern_to_index + ;; SHARED-NEXT: (tuple.extract 2 1 + ;; SHARED-NEXT: (local.get $2) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + + ;; SHARED: (func $exported_func (type $sig) (param $f (ref null (shared i31))) (param $e (ref null (shared i31))) (result (ref null (shared any))) + ;; SHARED-NEXT: (call $extern_to_any + ;; SHARED-NEXT: (call $index_to_extern + ;; SHARED-NEXT: (local.get $e) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; UNSHARED: (global $imported_global i31ref (ref.i31 + ;; UNSHARED-NEXT: (i32.const 0) + ;; UNSHARED-NEXT: )) + + ;; UNSHARED: (table $funcs 1 1 funcref) + + ;; UNSHARED: (table $externs 1 externref) + + ;; UNSHARED: (elem $funcs (table $funcs) (i32.const 0) func $exported_func) + + ;; UNSHARED: (elem $externs (table $externs) (i32.const 0) externref (item (global.get $imported_global$import))) + + ;; UNSHARED: (export "exported_func" (func $exported_func$export)) + + ;; UNSHARED: (func $imported_func (type $4) (param $0 i31ref) (param $1 i31ref) (result i31ref i31ref) + ;; UNSHARED-NEXT: (local $2 (tuple i31ref externref)) + ;; UNSHARED-NEXT: (local.set $2 + ;; UNSHARED-NEXT: (call $imported_func$import + ;; UNSHARED-NEXT: (local.get $0) + ;; UNSHARED-NEXT: (call $index_to_extern + ;; UNSHARED-NEXT: (local.get $1) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (tuple.make 2 + ;; UNSHARED-NEXT: (tuple.extract 2 0 + ;; UNSHARED-NEXT: (local.get $2) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (call $extern_to_index + ;; UNSHARED-NEXT: (tuple.extract 2 1 + ;; UNSHARED-NEXT: (local.get $2) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + + ;; UNSHARED: (func $exported_func (type $sig) (param $f i31ref) (param $e i31ref) (result anyref) + ;; UNSHARED-NEXT: (call $extern_to_any + ;; UNSHARED-NEXT: (call $index_to_extern + ;; UNSHARED-NEXT: (local.get $e) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + (func $exported_func (param $f funcref) (param $e externref) (result anyref) + ;; Exported function taking funcref and externref and returning anyref. + (any.convert_extern + (local.get $e) + ) + ) + + ;; SHARED: (func $basic-types (type $5) (param $a (ref null $array)) + ;; SHARED-NEXT: (local $nf (ref null (shared none))) + ;; SHARED-NEXT: (local $ne (ref null (shared none))) + ;; SHARED-NEXT: (local $str (ref null (shared i31))) + ;; SHARED-NEXT: (local $eq (ref null (shared eq))) + ;; SHARED-NEXT: (nop) + ;; SHARED-NEXT: ) + ;; UNSHARED: (func $basic-types (type $5) (param $a (ref null $array)) + ;; UNSHARED-NEXT: (local $nf nullref) + ;; UNSHARED-NEXT: (local $ne nullref) + ;; UNSHARED-NEXT: (local $str i31ref) + ;; UNSHARED-NEXT: (local $eq eqref) + ;; UNSHARED-NEXT: (nop) + ;; UNSHARED-NEXT: ) + (func $basic-types (param $a (ref null $array)) + ;; Test lowering of array and basic heap types in parameters and locals. + (local $nf nullfuncref) + (local $ne nullexternref) + (local $str stringref) + (local $eq eqref) + (nop) + ) + + ;; SHARED: (func $ref-func-and-global (type $6) (param $s (ref $struct)) + ;; SHARED-NEXT: (struct.set $struct 0 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: (ref.i31_shared + ;; SHARED-NEXT: (i32.const 0) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (struct.set $struct 1 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: (global.get $imported_global) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; UNSHARED: (func $ref-func-and-global (type $6) (param $s (ref $struct)) + ;; UNSHARED-NEXT: (struct.set $struct 0 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: (ref.i31 + ;; UNSHARED-NEXT: (i32.const 0) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (struct.set $struct 1 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: (global.get $imported_global) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + (func $ref-func-and-global (param $s (ref $struct)) + ;; Store ref.func and an imported externref global into struct fields. + (struct.set $struct 0 + (local.get $s) + (ref.func $exported_func) + ) + (struct.set $struct 1 + (local.get $s) + (global.get $imported_global) + ) + ) + + ;; SHARED: (func $call-ref (type $7) (param $s (ref $struct)) (param $f (ref (shared i31))) + ;; SHARED-NEXT: (struct.set $struct 2 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: (call_indirect $funcs (type $sig) + ;; SHARED-NEXT: (struct.get $struct 0 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (struct.get $struct 1 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (i31.get_u + ;; SHARED-NEXT: (local.get $f) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; UNSHARED: (func $call-ref (type $7) (param $s (ref $struct)) (param $f (ref i31)) + ;; UNSHARED-NEXT: (struct.set $struct 2 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: (call_indirect $funcs (type $sig) + ;; UNSHARED-NEXT: (struct.get $struct 0 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (struct.get $struct 1 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (i31.get_u + ;; UNSHARED-NEXT: (local.get $f) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + (func $call-ref (param $s (ref $struct)) (param $f (ref $sig)) + ;; Lower call_ref to call_indirect over the $funcs table. + (struct.set $struct 2 + (local.get $s) + (call_ref $sig + (struct.get $struct 0 + (local.get $s) + ) + (struct.get $struct 1 + (local.get $s) + ) + (local.get $f) + ) + ) + ) + + ;; SHARED: (func $call-imported-func-and-convert (type $8) (param $s (ref $struct)) (result (ref null (shared i31))) + ;; SHARED-NEXT: (tuple.drop 2 + ;; SHARED-NEXT: (call $imported_func + ;; SHARED-NEXT: (struct.get $struct 0 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (call $extern_to_index + ;; SHARED-NEXT: (call $any_to_extern + ;; SHARED-NEXT: (struct.get $struct 2 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (call $extern_to_index + ;; SHARED-NEXT: (call $any_to_extern + ;; SHARED-NEXT: (struct.get $struct 2 + ;; SHARED-NEXT: (local.get $s) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; UNSHARED: (func $call-imported-func-and-convert (type $8) (param $s (ref $struct)) (result i31ref) + ;; UNSHARED-NEXT: (tuple.drop 2 + ;; UNSHARED-NEXT: (call $imported_func + ;; UNSHARED-NEXT: (struct.get $struct 0 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (call $extern_to_index + ;; UNSHARED-NEXT: (call $any_to_extern + ;; UNSHARED-NEXT: (struct.get $struct 2 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (call $extern_to_index + ;; UNSHARED-NEXT: (call $any_to_extern + ;; UNSHARED-NEXT: (struct.get $struct 2 + ;; UNSHARED-NEXT: (local.get $s) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + (func $call-imported-func-and-convert (param $s (ref $struct)) (result externref) + ;; Convert anyref to externref and call an imported function. + (tuple.drop 2 + (call $imported_func + (struct.get $struct 0 + (local.get $s) + ) + (extern.convert_any + (struct.get $struct 2 + (local.get $s) + ) + ) + ) + ) + (extern.convert_any + (struct.get $struct 2 + (local.get $s) + ) + ) + ) + + ;; SHARED: (func $test-tag (type $9) (param $e (ref null (shared i31))) (result (ref null (shared i31))) + ;; SHARED-NEXT: (try (result (ref null (shared i31))) + ;; SHARED-NEXT: (do + ;; SHARED-NEXT: (throw $tag + ;; SHARED-NEXT: (call $index_to_extern + ;; SHARED-NEXT: (local.get $e) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: (catch $tag + ;; SHARED-NEXT: (call $extern_to_index + ;; SHARED-NEXT: (pop externref) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; SHARED-NEXT: ) + ;; UNSHARED: (func $test-tag (type $9) (param $e i31ref) (result i31ref) + ;; UNSHARED-NEXT: (try (result i31ref) + ;; UNSHARED-NEXT: (do + ;; UNSHARED-NEXT: (throw $tag + ;; UNSHARED-NEXT: (call $index_to_extern + ;; UNSHARED-NEXT: (local.get $e) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: (catch $tag + ;; UNSHARED-NEXT: (call $extern_to_index + ;; UNSHARED-NEXT: (pop externref) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + ;; UNSHARED-NEXT: ) + (func $test-tag (param $e externref) (result externref) + ;; Throw and catch an externref tag with i31ref table conversions. + (try (result externref) + (do + (throw $tag + (local.get $e) + ) + ) + (catch $tag + (pop externref) + ) + ) + ) +) +;; SHARED: (func $exported_func$export (type $11) (param $0 (ref null (shared i31))) (param $1 externref) (result (ref null (shared any))) +;; SHARED-NEXT: (call $exported_func +;; SHARED-NEXT: (local.get $0) +;; SHARED-NEXT: (call $extern_to_index +;; SHARED-NEXT: (local.get $1) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) + +;; SHARED: (func $extern_to_index (type $12) (param $0 externref) (result (ref null (shared i31))) +;; SHARED-NEXT: (local $1 i32) +;; SHARED-NEXT: (if (result (ref null (shared i31))) +;; SHARED-NEXT: (ref.is_null +;; SHARED-NEXT: (local.get $0) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (then +;; SHARED-NEXT: (ref.null (shared none)) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (else +;; SHARED-NEXT: (if (result (ref (shared i31))) +;; SHARED-NEXT: (i32.ge_s +;; SHARED-NEXT: (local.tee $1 +;; SHARED-NEXT: (table.grow $externs +;; SHARED-NEXT: (local.get $0) +;; SHARED-NEXT: (i32.const 1) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (i32.const 0) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (then +;; SHARED-NEXT: (ref.i31_shared +;; SHARED-NEXT: (local.get $1) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (else +;; SHARED-NEXT: (unreachable) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) + +;; SHARED: (func $index_to_extern (type $13) (param $0 (ref null (shared i31))) (result externref) +;; SHARED-NEXT: (if (result externref) +;; SHARED-NEXT: (ref.is_null +;; SHARED-NEXT: (local.get $0) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (then +;; SHARED-NEXT: (ref.null noextern) +;; SHARED-NEXT: ) +;; SHARED-NEXT: (else +;; SHARED-NEXT: (table.get $externs +;; SHARED-NEXT: (i31.get_u +;; SHARED-NEXT: (local.get $0) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) +;; SHARED-NEXT: ) + +;; UNSHARED: (func $exported_func$export (type $11) (param $0 i31ref) (param $1 externref) (result anyref) +;; UNSHARED-NEXT: (call $exported_func +;; UNSHARED-NEXT: (local.get $0) +;; UNSHARED-NEXT: (call $extern_to_index +;; UNSHARED-NEXT: (local.get $1) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) + +;; UNSHARED: (func $extern_to_index (type $12) (param $0 externref) (result i31ref) +;; UNSHARED-NEXT: (local $1 i32) +;; UNSHARED-NEXT: (if (result i31ref) +;; UNSHARED-NEXT: (ref.is_null +;; UNSHARED-NEXT: (local.get $0) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (then +;; UNSHARED-NEXT: (ref.null none) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (else +;; UNSHARED-NEXT: (if (result (ref i31)) +;; UNSHARED-NEXT: (i32.ge_s +;; UNSHARED-NEXT: (local.tee $1 +;; UNSHARED-NEXT: (table.grow $externs +;; UNSHARED-NEXT: (local.get $0) +;; UNSHARED-NEXT: (i32.const 1) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (i32.const 0) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (then +;; UNSHARED-NEXT: (ref.i31 +;; UNSHARED-NEXT: (local.get $1) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (else +;; UNSHARED-NEXT: (unreachable) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) + +;; UNSHARED: (func $index_to_extern (type $13) (param $0 i31ref) (result externref) +;; UNSHARED-NEXT: (if (result externref) +;; UNSHARED-NEXT: (ref.is_null +;; UNSHARED-NEXT: (local.get $0) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (then +;; UNSHARED-NEXT: (ref.null noextern) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: (else +;; UNSHARED-NEXT: (table.get $externs +;; UNSHARED-NEXT: (i31.get_u +;; UNSHARED-NEXT: (local.get $0) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: ) +;; UNSHARED-NEXT: )