Coverage for tests/test_refs.py: 98%

103 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-20 16:25 +0000

1import unittest 

2from typing import cast 

3 

4from wasmtime import * 

5 

6 

7def ref_types_store(): 

8 config = Config() 

9 config.wasm_reference_types = True 

10 engine = Engine(config) 

11 return Store(engine) 

12 

13 

14def compile_and_instantiate(wat): 

15 store = ref_types_store() 

16 module = Module(store.engine, wat) 

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

18 

19 

20class SetHitOnDrop: 

21 def __init__(self, obj): 

22 obj['hit'] = False 

23 self.obj = obj 

24 

25 def __del__(self): 

26 self.obj['hit'] = True 

27 

28 

29class TestExternRef(unittest.TestCase): 

30 def test_smoke(self): 

31 (instance, store) = compile_and_instantiate( 

32 """ 

33 (module 

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

35 local.get 0 

36 ) 

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

38 ref.null extern 

39 ) 

40 ) 

41 """ 

42 ) 

43 

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

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

46 

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

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

49 

50 for extern in externs: 

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

52 ref = Val.externref(extern) 

53 

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

55 self.assertEqual(ref.value, extern) 

56 

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

58 # extern data. 

59 result = f(store, ref) 

60 self.assertEqual(result, extern) 

61 

62 def test_int_to_externref(self): 

63 wat = """ 

64 (module 

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

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

67 ) 

68 """ 

69 config = Config() 

70 config.wasm_reference_types = True 

71 engine = Engine(config) 

72 store = Store(engine) 

73 module = Module(store.engine, wat) 

74 linker = Linker(engine) 

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

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

77 instance = linker.instantiate(store, module) 

78 f: Func 

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

80 f(store, 5) 

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

82 f(store, 5.7) 

83 

84 def test_externref_tables(self): 

85 store = ref_types_store() 

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

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

88 

89 for i in range(0, 10): 

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

91 

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

93 

94 for i in range(0, 10): 

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

96 for i in range(10, 12): 

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

98 

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

100 

101 for i in range(0, 7): 

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

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

104 for i in range(8, 10): 

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

106 for i in range(10, 12): 

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

108 

109 def test_externref_in_global(self): 

110 store = ref_types_store() 

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

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

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

114 g.set_value(store, "goodbye") 

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

116 

117 def test_dtor_global(self): 

118 obj = {} # type: ignore 

119 store = ref_types_store() 

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

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

122 assert(not obj['hit']) 

123 g.set_value(store, None) 

124 assert(obj['hit']) 

125 

126 def test_dtor_func(self): 

127 (instance, store) = compile_and_instantiate( 

128 """ 

129 (module 

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

131 ) 

132 """ 

133 ) 

134 

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

136 obj = {} # type: ignore 

137 f(store, SetHitOnDrop(obj)) 

138 store.gc() 

139 assert(obj['hit']) 

140 

141 

142class TestFuncRef(unittest.TestCase): 

143 def test_smoke(self): 

144 (instance, store) = compile_and_instantiate( 

145 """ 

146 (module 

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

148 local.get 0 

149 ) 

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

151 ref.null func 

152 ) 

153 ) 

154 """ 

155 ) 

156 

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

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

159 

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

161 

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

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

164 

165 # We can create a funcref. 

166 ref_g_val = Val.funcref(g) 

167 

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

169 g2 = ref_g_val.as_funcref() 

170 if isinstance(g2, Func): 

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

172 else: 

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

174 

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

176 g3 = f(store, ref_g_val) 

177 if isinstance(g3, Func): 

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

179 else: 

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