[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.
diff --git a/src/passes/MakeSharedObjects.cpp b/src/passes/MakeSharedObjects.cpp index 044e44f..6149869 100644 --- a/src/passes/MakeSharedObjects.cpp +++ b/src/passes/MakeSharedObjects.cpp
@@ -113,6 +113,13 @@ 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 $<t>_to_index (param $ref <t>) (result (ref null (shared i31))) // (local $idx i32) @@ -141,10 +148,10 @@ // ) 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 @@ 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 @@ // ) 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 @@ 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 MakeSharedObjects : WalkerPass<PostWalker<MakeSharedObjects, UnifiedExpressionVisitor<MakeSharedObjects>>> { + Shareability shared = Shared; Type funcref = Type(HeapTypes::func, Nullable); Type externref = Type(HeapTypes::ext, Nullable); @@ -315,19 +323,19 @@ 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 @@ 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<CallRef*, HeapType> callRefTypes; @@ -702,7 +710,7 @@ 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 @@ 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 @@ } 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 @@ builder[i].subTypeOf(builder[info.indices.at(*super)]); } } else { - builder[i].setShared(Shared); + builder[i].setShared(shared); } } @@ -967,7 +982,7 @@ } 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 @@ 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 0000000..16b5d72 --- /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: )