Coverage for tests/test_refs.py: 98%

107 statements  

« prev     ^ index     » next       coverage.py v7.11.3, created at 2025-12-01 19:40 +0000

1import unittest 

2from typing import cast 

3import gc 

4 

5from wasmtime import * 

6 

7 

8def ref_types_store(): 

9 config = Config() 

10 config.wasm_reference_types = True 

11 engine = Engine(config) 

12 return Store(engine) 

13 

14 

15def compile_and_instantiate(wat): 

16 store = ref_types_store() 

17 module = Module(store.engine, wat) 

18 return (Instance(store, module, []), store) 

19 

20 

21class SetHitOnDrop: 

22 def __init__(self, obj): 

23 obj['hit'] = False 

24 self.obj = obj 

25 

26 def __del__(self): 

27 self.obj['hit'] = True 

28 

29 

30class TestExternRef(unittest.TestCase): 

31 def test_smoke(self): 

32 (instance, store) = compile_and_instantiate( 

33 """ 

34 (module 

35 (func (export "f") (param externref) (result externref) 

36 local.get 0 

37 ) 

38 (func (export "null_externref") (result externref) 

39 ref.null extern 

40 ) 

41 ) 

42 """ 

43 ) 

44 

45 null_externref = instance.exports(store).get("null_externref") 

46 self.assertEqual(null_externref(store), None) 

47 

48 f = instance.exports(store).get("f") 

49 externs = [42, True, False, None, "Hello", {"x": 1}, [12, 13, 14], Config()] 

50 

51 for extern in externs: 

52 # We can create an externref for the given extern data. 

53 ref = Val.externref(extern) 

54 

55 # And the externref's value is our extern data. 

56 self.assertEqual(ref.value, extern) 

57 

58 # And we can round trip the externref through Wasm and still get our 

59 # extern data. 

60 result = f(store, ref) 

61 self.assertEqual(result, extern) 

62 

63 def test_int_to_externref(self): 

64 wat = """ 

65 (module 

66 (import "env" "int_to_ref" (func $int_to_ref (param $a externref) (result externref))) 

67 (export "test" (func $int_to_ref)) 

68 ) 

69 """ 

70 config = Config() 

71 config.wasm_reference_types = True 

72 engine = Engine(config) 

73 store = Store(engine) 

74 module = Module(store.engine, wat) 

75 linker = Linker(engine) 

76 ftype = FuncType([ValType.externref()], [ValType.externref()]) 

77 linker.define_func("env", "int_to_ref", ftype, lambda x: x) 

78 instance = linker.instantiate(store, module) 

79 f: Func 

80 f = cast(Func, instance.exports(store).get("test")) 

81 f(store, 5) 

82 f = cast(Func, instance.exports(store).get("test")) 

83 f(store, 5.7) 

84 

85 def test_externref_tables(self): 

86 store = ref_types_store() 

87 ty = TableType(ValType.externref(), Limits(10, None)) 

88 table = Table(store, ty, "init") 

89 

90 for i in range(0, 10): 

91 self.assertEqual(table.get(store, i), "init") 

92 

93 table.grow(store, 2, "grown") 

94 

95 for i in range(0, 10): 

96 self.assertEqual(table.get(store, i), "init") 

97 for i in range(10, 12): 

98 self.assertEqual(table.get(store, i), "grown") 

99 

100 table.set(store, 7, "lucky") 

101 

102 for i in range(0, 7): 

103 self.assertEqual(table.get(store, i), "init") 

104 self.assertEqual(table.get(store, 7), "lucky") 

105 for i in range(8, 10): 

106 self.assertEqual(table.get(store, i), "init") 

107 for i in range(10, 12): 

108 self.assertEqual(table.get(store, i), "grown") 

109 

110 def test_externref_in_global(self): 

111 store = ref_types_store() 

112 ty = GlobalType(ValType.externref(), True) 

113 g = Global(store, ty, Val.externref("hello")) 

114 self.assertEqual(g.value(store), "hello") 

115 g.set_value(store, "goodbye") 

116 self.assertEqual(g.value(store), "goodbye") 

117 

118 def test_dtor_global(self): 

119 obj = {} # type: ignore 

120 store = ref_types_store() 

121 ty = GlobalType(ValType.externref(), True) 

122 g = Global(store, ty, Val.externref(SetHitOnDrop(obj))) 

123 assert(not obj['hit']) 

124 g.set_value(store, None) 

125 store.gc() 

126 gc.collect() 

127 assert(obj['hit']) 

128 

129 def test_dtor_func(self): 

130 (instance, store) = compile_and_instantiate( 

131 """ 

132 (module 

133 (func (export "f") (param externref)) 

134 ) 

135 """ 

136 ) 

137 

138 f = instance.exports(store).get("f") 

139 obj = {} # type: ignore 

140 f(store, SetHitOnDrop(obj)) 

141 store.gc() 

142 gc.collect() 

143 assert(obj['hit']) 

144 

145 

146class TestFuncRef(unittest.TestCase): 

147 def test_smoke(self): 

148 (instance, store) = compile_and_instantiate( 

149 """ 

150 (module 

151 (func (export \"f\") (param funcref) (result funcref) 

152 local.get 0 

153 ) 

154 (func (export "null_funcref") (result funcref) 

155 ref.null func 

156 ) 

157 ) 

158 """ 

159 ) 

160 

161 null_funcref = instance.exports(store).get("null_funcref") 

162 self.assertEqual(null_funcref(store), None) 

163 

164 f = instance.exports(store).get("f") 

165 

166 ty = FuncType([], [ValType.i32()]) 

167 g = Func(store, ty, lambda: 42) 

168 

169 # We can create a funcref. 

170 ref_g_val = Val.funcref(g) 

171 

172 # And the funcref's points to `g`. 

173 g2 = ref_g_val.as_funcref() 

174 if isinstance(g2, Func): 

175 self.assertEqual(g2(store), 42) 

176 else: 

177 self.fail("g2 is not a funcref: g2 = %r" % g2) 

178 

179 # And we can round trip the funcref through Wasm. 

180 g3 = f(store, ref_g_val) 

181 if isinstance(g3, Func): 

182 self.assertEqual(g3(store), 42) 

183 else: 

184 self.fail("g3 is not a funcref: g3 = %r" % g3)