Coverage for tests/codegen/__init__.py: 85%

20 statements  

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

1# The `codegen` directory here is intended to test the bindings generator for 

2# components in Python. Each file represents a distinct test where an input 

3# wasm file is bound and then the generated bindings are imported dynamically. 

4# 

5# This structure is done so a general `pytest` will execute everything, 

6# generating bindings during test collection and otherwise setting up everything 

7# to be naturally checked with mypy and other tests configured. 

8 

9from wasmtime import wat2wasm 

10from wasmtime.bindgen import generate 

11from pathlib import Path 

12import os 

13 

14 

15# Helper function to generate bindings for the `wat` specified into the 

16# `generated` sub-folder. After calling this method the bindings can be 

17# imported with: 

18# 

19# from .generated.name import Name 

20# 

21# and then used to type-check everything. 

22def bindgen(name: str, wat: str) -> None: 

23 files = generate(name, wat2wasm(wat)) 

24 root = Path(__file__).parent.joinpath('generated') 

25 dst = root.joinpath(name) 

26 for name, contents in files.items(): 

27 # If the file already has the desired contents then skip writing. This 

28 # is an attempt to fix CI issues on windows. 

29 file = dst.joinpath(name) 

30 if file.exists(): 

31 with open(file, 'rb') as f: 

32 if f.read() == contents: 

33 continue 

34 

35 # Write the contents to a temporary file and then attempt to atomically 

36 # replace the previous file, if any, with the new contents. This 

37 # is done to hopefully fix an apparent issue in `pytest` where it seems 

38 # that there are multiple threads of the python interpreter, perhaps for 

39 # pytest itself, mypy, and flake8, and overwriting files in-place causes 

40 # issues are partial files may be seen. 

41 tmp_file = file.with_suffix('.tmp') 

42 if not file.parent.exists(): 

43 file.parent.mkdir(parents=True) 

44 tmp_file.write_bytes(contents) 

45 os.replace(tmp_file, file) 

46 

47 

48REALLOC = """ 

49 (global $last (mut i32) (i32.const 1000)) 

50 (func $realloc (export "realloc") 

51 (param $old_ptr i32) 

52 (param $old_size i32) 

53 (param $align i32) 

54 (param $new_size i32) 

55 (result i32) 

56 

57 (local $ret i32) 

58 

59 ;; Test if the old pointer is non-null 

60 local.get $old_ptr 

61 if 

62 ;; If the old size is bigger than the new size then 

63 ;; this is a shrink and transparently allow it 

64 local.get $old_size 

65 local.get $new_size 

66 i32.gt_u 

67 if 

68 local.get $old_ptr 

69 return 

70 end 

71 

72 ;; otherwise fall through to allocate a new chunk which will later 

73 ;; copy data over 

74 end 

75 

76 ;; align up `$last` 

77 (global.set $last 

78 (i32.and 

79 (i32.add 

80 (global.get $last) 

81 (i32.add 

82 (local.get $align) 

83 (i32.const -1))) 

84 (i32.xor 

85 (i32.add 

86 (local.get $align) 

87 (i32.const -1)) 

88 (i32.const -1)))) 

89 

90 ;; save the current value of `$last` as the return value 

91 global.get $last 

92 local.set $ret 

93 

94 ;; bump our pointer 

95 (global.set $last 

96 (i32.add 

97 (global.get $last) 

98 (local.get $new_size))) 

99 

100 ;; while `memory.size` is less than `$last`, grow memory 

101 ;; by one page 

102 (loop $loop 

103 (if 

104 (i32.lt_u 

105 (i32.mul (memory.size) (i32.const 65536)) 

106 (global.get $last)) 

107 (then 

108 i32.const 1 

109 memory.grow 

110 ;; test to make sure growth succeeded 

111 i32.const -1 

112 i32.eq 

113 if unreachable end 

114 

115 br $loop))) 

116 

117 

118 ;; ensure anything necessary is set to valid data by spraying a bit 

119 ;; pattern that is invalid 

120 local.get $ret 

121 i32.const 0xde 

122 local.get $new_size 

123 memory.fill 

124 

125 ;; If the old pointer is present then that means this was a reallocation 

126 ;; of an existing chunk which means the existing data must be copied. 

127 local.get $old_ptr 

128 if 

129 local.get $ret ;; destination 

130 local.get $old_ptr ;; source 

131 local.get $old_size ;; size 

132 memory.copy 

133 end 

134 

135 local.get $ret 

136 ) 

137"""