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: )