quickwin 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/README.en.md +3 -0
  2. package/README.md +2 -0
  3. package/lib/abort.d.ts +21 -0
  4. package/lib/assert.d.ts +2 -0
  5. package/lib/bitmap.d.ts +7 -0
  6. package/lib/cache-utils.d.ts +6 -0
  7. package/lib/certs.d.ts +1 -0
  8. package/lib/dpi.d.ts +9 -0
  9. package/lib/dumpRects.d.ts +2 -0
  10. package/lib/exec-log.d.ts +23 -0
  11. package/lib/fetch.d.ts +4 -0
  12. package/lib/ffi/bind.d.ts +70 -0
  13. package/lib/ffi/ctype.d.ts +117 -0
  14. package/lib/ffi/index.d.ts +2 -0
  15. package/lib/ffi/struct.d.ts +174 -0
  16. package/lib/http-common.d.ts +143 -0
  17. package/lib/http-server.d.ts +59 -0
  18. package/lib/polyfill.d.ts +22 -0
  19. package/lib/react-qw/components/Button.d.ts +9 -0
  20. package/lib/react-qw/components/CheckBox.d.ts +11 -0
  21. package/lib/react-qw/components/ComboBox.d.ts +11 -0
  22. package/lib/react-qw/components/DateTimePicker.d.ts +15 -0
  23. package/lib/react-qw/components/Input.d.ts +15 -0
  24. package/lib/react-qw/components/Link.d.ts +12 -0
  25. package/lib/react-qw/components/ListBox.d.ts +13 -0
  26. package/lib/react-qw/components/ListView.d.ts +37 -0
  27. package/lib/react-qw/components/PathPicker.d.ts +23 -0
  28. package/lib/react-qw/components/ProgressBar.d.ts +9 -0
  29. package/lib/react-qw/components/RadioButton.d.ts +11 -0
  30. package/lib/react-qw/components/ScrollView.d.ts +9 -0
  31. package/lib/react-qw/components/Slider.d.ts +12 -0
  32. package/lib/react-qw/components/Tab.d.ts +14 -0
  33. package/lib/react-qw/components/Tooltip.d.ts +7 -0
  34. package/lib/react-qw/components/TreeView.d.ts +18 -0
  35. package/lib/react-qw/components/index.d.ts +16 -0
  36. package/lib/react-qw/index.d.ts +24 -0
  37. package/lib/react-qw/layout.d.ts +29 -0
  38. package/lib/react-qw/nmhdr.d.ts +1 -0
  39. package/lib/react-qw/props.d.ts +2 -0
  40. package/lib/react-qw/reconciler.d.ts +21 -0
  41. package/lib/stream.d.ts +20 -0
  42. package/lib/text-codec.d.ts +39 -0
  43. package/lib/text-measure.d.ts +14 -0
  44. package/lib/url.d.ts +54 -0
  45. package/lib/websocket.d.ts +73 -0
  46. package/lib/windows/{advapi32.ts → advapi32.d.ts} +6 -21
  47. package/lib/windows/comctl32.d.ts +14 -0
  48. package/lib/windows/comdlg32.d.ts +4 -0
  49. package/lib/windows/{gdi32.ts → gdi32.d.ts} +161 -98
  50. package/lib/windows/{kernel32.ts → kernel32.d.ts} +138 -115
  51. package/lib/windows/{msimg32.ts → msimg32.d.ts} +11 -14
  52. package/lib/windows/ntdll.d.ts +5 -0
  53. package/lib/windows/ole32.d.ts +3 -0
  54. package/lib/windows/{psapi.ts → psapi.d.ts} +9 -18
  55. package/lib/windows/{shell32.ts → shell32.d.ts} +25 -24
  56. package/lib/windows/structs.d.ts +3141 -0
  57. package/lib/windows/{user32.ts → user32.d.ts} +196 -193
  58. package/lib/windows/version.d.ts +27 -0
  59. package/lib/windows/{winspool.ts → winspool.d.ts} +18 -32
  60. package/package.json +15 -8
  61. package/qwin-nowasm-x86.exe +0 -0
  62. package/qwin-nowasm.exe +0 -0
  63. package/qwin-x86.exe +0 -0
  64. package/qwin.exe +0 -0
  65. package/examples/PdfCanvas.js +0 -38
  66. package/examples/PdfCanvas.tsx +0 -54
  67. package/examples/execd/main.js +0 -23379
  68. package/examples/execd/tray.js +0 -192
  69. package/examples/execd/worker.js +0 -122
  70. package/examples/pdf_preview2.js +0 -398
  71. package/examples/pdf_preview2.ts +0 -353
  72. package/examples/pdf_viewer.js +0 -22515
  73. package/examples/pdf_viewer.tsx +0 -228
  74. package/examples/test_gallery.js +0 -18692
  75. package/examples/test_gallery.tsx +0 -291
  76. package/examples/test_react_lazy.js +0 -18560
  77. package/examples/test_react_lazy.tsx +0 -65
  78. package/examples/test_react_listbox.js +0 -18562
  79. package/examples/test_react_listbox.tsx +0 -73
  80. package/examples/test_root_window.js +0 -18532
  81. package/examples/test_root_window.tsx +0 -41
  82. package/examples/test_tab.js +0 -18563
  83. package/examples/test_tab.tsx +0 -77
  84. package/examples/tray_demo.js +0 -86
  85. package/examples/tray_demo.tsx +0 -89
  86. package/lib/abort.ts +0 -69
  87. package/lib/assert.ts +0 -7
  88. package/lib/bitmap.ts +0 -39
  89. package/lib/cache-utils.ts +0 -40
  90. package/lib/certs.ts +0 -258
  91. package/lib/dpi.ts +0 -31
  92. package/lib/dumpRects.ts +0 -34
  93. package/lib/exec-log.ts +0 -30
  94. package/lib/fetch.ts +0 -589
  95. package/lib/ffi/bind.ts +0 -540
  96. package/lib/ffi/ctype.ts +0 -371
  97. package/lib/ffi/index.ts +0 -6
  98. package/lib/ffi/struct.ts +0 -780
  99. package/lib/http-common.ts +0 -441
  100. package/lib/http-server.ts +0 -604
  101. package/lib/polyfill.ts +0 -171
  102. package/lib/react-qw/components/index.ts +0 -17
  103. package/lib/react-qw/index.ts +0 -96
  104. package/lib/react-qw/layout.ts +0 -111
  105. package/lib/react-qw/nmhdr.ts +0 -7
  106. package/lib/react-qw/props.ts +0 -41
  107. package/lib/react-qw/reconciler.ts +0 -379
  108. package/lib/stream.ts +0 -22
  109. package/lib/text-codec.ts +0 -171
  110. package/lib/text-measure.ts +0 -44
  111. package/lib/url.ts +0 -201
  112. package/lib/websocket.ts +0 -600
  113. package/lib/windows/comctl32.ts +0 -20
  114. package/lib/windows/comdlg32.ts +0 -10
  115. package/lib/windows/ntdll.ts +0 -11
  116. package/lib/windows/ole32.ts +0 -9
  117. package/lib/windows/structs.ts +0 -807
  118. package/lib/windows/version.ts +0 -35
  119. package/test/add.wasm +0 -0
  120. package/test/bench_ffi_callraw.js +0 -235
  121. package/test/bench_ffi_callraw.ts +0 -235
  122. package/test/bench_ffi_overhead.js +0 -139
  123. package/test/bench_ffi_overhead.ts +0 -141
  124. package/test/bench_sendmessage.js +0 -104
  125. package/test/bench_sendmessage.ts +0 -100
  126. package/test/bench_sendmessage_nonnull.js +0 -187
  127. package/test/bench_sendmessage_nonnull.ts +0 -188
  128. package/test/complex.wasm +0 -0
  129. package/test/complex_imports.wasm +0 -0
  130. package/test/debug/http_server_e2e.js +0 -31
  131. package/test/debug/minwasm.js +0 -52
  132. package/test/debug/mupdf_debug.js +0 -86
  133. package/test/debug/wasm.js +0 -122
  134. package/test/debug/wasm_export_debug.js +0 -54
  135. package/test/debug/wasm_names.js +0 -36
  136. package/test/example.pdf +0 -0
  137. package/test/global_imports.wasm +0 -0
  138. package/test/import_func.wasm +0 -0
  139. package/test/imports.wasm +0 -0
  140. package/test/mupdf-cdn.js +0 -40
  141. package/test/mupdf-cdn.ts +0 -43
  142. package/test/run.js +0 -111
  143. package/test/run.ts +0 -116
  144. package/test/sjlj.wasm +0 -0
  145. package/test/test_basic.js +0 -7
  146. package/test/test_basic.ts +0 -9
  147. package/test/test_basic_fetch.js +0 -63
  148. package/test/test_basic_fetch.ts +0 -59
  149. package/test/test_brotli.js +0 -48
  150. package/test/test_brotli.ts +0 -52
  151. package/test/test_fetch_cache.js +0 -169
  152. package/test/test_fetch_cache.ts +0 -187
  153. package/test/test_ffi.js +0 -157
  154. package/test/test_ffi.ts +0 -170
  155. package/test/test_ffi_abi.js +0 -290
  156. package/test/test_ffi_abi.ts +0 -274
  157. package/test/test_ffi_array.js +0 -116
  158. package/test/test_ffi_array.ts +0 -141
  159. package/test/test_ffi_bind.js +0 -656
  160. package/test/test_ffi_bind.ts +0 -670
  161. package/test/test_ffi_struct.js +0 -779
  162. package/test/test_ffi_struct.ts +0 -828
  163. package/test/test_ffi_struct_layout.js +0 -495
  164. package/test/test_ffi_struct_layout.ts +0 -543
  165. package/test/test_ffi_user32.js +0 -103
  166. package/test/test_ffi_user32.ts +0 -113
  167. package/test/test_ffi_windows.js +0 -172
  168. package/test/test_ffi_windows.ts +0 -187
  169. package/test/test_files.js +0 -102
  170. package/test/test_files.ts +0 -121
  171. package/test/test_frame_encoding.js +0 -128
  172. package/test/test_frame_encoding.ts +0 -132
  173. package/test/test_gdi_draw.js +0 -681
  174. package/test/test_gdi_draw.ts +0 -725
  175. package/test/test_helper.js +0 -91
  176. package/test/test_helper.ts +0 -88
  177. package/test/test_http_import.js +0 -96
  178. package/test/test_http_import.ts +0 -93
  179. package/test/test_http_server.js +0 -214
  180. package/test/test_http_server.ts +0 -211
  181. package/test/test_import_dir.js +0 -4
  182. package/test/test_import_dir.ts +0 -5
  183. package/test/test_ipv6.js +0 -134
  184. package/test/test_ipv6.ts +0 -130
  185. package/test/test_jsx.js +0 -1314
  186. package/test/test_meta_url.js +0 -3
  187. package/test/test_meta_url.ts +0 -4
  188. package/test/test_mupdf_render.js +0 -51
  189. package/test/test_mupdf_render.ts +0 -55
  190. package/test/test_mupdf_twice.js +0 -62
  191. package/test/test_mupdf_twice.ts +0 -65
  192. package/test/test_mupdf_wasm.js +0 -39
  193. package/test/test_mupdf_wasm.ts +0 -32
  194. package/test/test_net_event.js +0 -57
  195. package/test/test_net_event.ts +0 -56
  196. package/test/test_net_fetch.js +0 -384
  197. package/test/test_net_fetch.ts +0 -373
  198. package/test/test_net_websocket.js +0 -180
  199. package/test/test_net_websocket.ts +0 -164
  200. package/test/test_polyfill.js +0 -144
  201. package/test/test_polyfill.ts +0 -159
  202. package/test/test_printer.js +0 -137
  203. package/test/test_printer.ts +0 -148
  204. package/test/test_proc.js +0 -141
  205. package/test/test_proc.ts +0 -163
  206. package/test/test_react_complex.js +0 -18678
  207. package/test/test_react_counter.js +0 -18555
  208. package/test/test_react_flex.js +0 -18871
  209. package/test/test_react_hidden.js +0 -18560
  210. package/test/test_react_listview_link.js +0 -18590
  211. package/test/test_react_notify.js +0 -18797
  212. package/test/test_react_render.js +0 -18550
  213. package/test/test_registry.js +0 -74
  214. package/test/test_registry.ts +0 -95
  215. package/test/test_sysinfo.js +0 -122
  216. package/test/test_sysinfo.ts +0 -141
  217. package/test/test_url.js +0 -173
  218. package/test/test_url.ts +0 -183
  219. package/test/test_wasm_basic.js +0 -85
  220. package/test/test_wasm_basic.ts +0 -73
  221. package/test/test_wasm_import_global.js +0 -41
  222. package/test/test_wasm_import_global.ts +0 -45
  223. package/test/test_wasm_sjlj.js +0 -145
  224. package/test/test_wasm_sjlj.ts +0 -125
  225. package/test/test_wasm_types.js +0 -97
  226. package/test/test_wasm_types.ts +0 -124
  227. package/test/test_wolfssl_read.js +0 -203
  228. package/test/test_wolfssl_read.ts +0 -184
  229. package/test/test_worker.js +0 -21
  230. package/test/test_worker.ts +0 -24
  231. package/test/test_worker_concurrent.js +0 -45
  232. package/test/test_worker_concurrent.ts +0 -56
  233. package/test/test_worker_data_url.js +0 -46
  234. package/test/test_worker_data_url.ts +0 -51
  235. package/test/test_worker_fetch.js +0 -26
  236. package/test/test_worker_fetch.ts +0 -27
  237. package/test/test_worker_net.js +0 -69
  238. package/test/test_worker_net.ts +0 -66
  239. package/test/test_worker_wasm_concurrent.js +0 -44
  240. package/test/test_worker_wasm_concurrent.ts +0 -45
  241. package/test/types.wasm +0 -0
  242. package/test/worker_fetch.js +0 -13
  243. package/test/worker_fetch.ts +0 -13
  244. package/test/worker_helper.js +0 -1
  245. package/test/worker_helper.ts +0 -1
  246. package/test/worker_http.js +0 -18
  247. package/test/worker_http.ts +0 -20
  248. package/test/worker_import_lib.js +0 -12
  249. package/test/worker_import_lib.ts +0 -13
  250. package/test/worker_module.js +0 -16
  251. package/test/worker_module.ts +0 -17
  252. package/test/worker_wasm_concurrent.js +0 -22
  253. package/test/worker_wasm_concurrent.ts +0 -22
@@ -1,188 +0,0 @@
1
- // 一次性性能 bench:FFI 签名 '!' 标注的调用时 0 检验成本(同函数多臂对照 + A/A 噪声底)
2
- // 不入 CI。用法:make js 后 POST /exec {"cmd":"qwin.exe test/bench_sendmessage_nonnull.js"}
3
- // 臂(同一 proc 各自 bind,唯一变量是 '!'):
4
- // A1 base '<HWND>ptr u32 <>ptr <>ptr -> <>ptr' 基线
5
- // A2 ctrl '<HWND>ptr u32 <>ptr <>ptr -> <>ptr' 与 A1 完全同签名——两臂差值 = 机器噪声底
6
- // B arg! '<HWND>ptr! u32 <>ptr <>ptr -> <>ptr' + 参数位 arg#1 0 检查
7
- // C ret! '<HWND>ptr! u32 <>ptr <>ptr -> <>ptr!' + 返回位 0 检查(仅非零返回场景)
8
- // 方法学(前两轮教训):批量缩到 50k/样本 → 臂序每 ~650ms 轮转一次,抵消 QEMU 调度抖动;
9
- // S1/S3 各臂 30 样本取 median(对 GC/调度离群稳健);A2-A1 是效应检验的参照带——
10
- // B/A 落在 A2/A 带内即「低于噪声底,不可测」。'!' 边际 = 每标注位 1 次整数 === 比较
11
- // (endsWith 无条件跑、所有臂共模),理论 ≪ 轮噪声。
12
- // C 臂标了返回 '!',撞真实 0 即 throw —— 先用 A1 探各场景原始返回值,非零才让 C 进。
13
- // 全部消息发自有窗口(直调 wndproc)。结束必须 DestroyWindow + std.exit。
14
- import * as std from 'std'
15
- import * as gui from 'gui'
16
- import { bind, WCHAR } from '../lib/ffi/bind.js'
17
- import { PtrArrayBuffer } from '../lib/ffi/ctype.js'
18
-
19
- const BATCH = 50_000 // 每样本批量(~650ms)——小批量快轮转,去相关调度抖动
20
- const ROUNDS = 30 // S1/S3 每臂样本数(30 × 3-4 臂 ≈ 60-80s/suite)
21
- const N_S2 = 50_000
22
- const ROUNDS_S2 = 7
23
- const WM_NULL = 0x0000
24
- const WM_SETTEXT = 0x000c
25
- const WM_GETTEXT = 0x000d
26
-
27
- // median(离群稳健)供 micro 与 suite 共用
28
- const med = (t: number[]): number => {
29
- const s = [...t].sort((x, y) => x - y)
30
- const m = s.length >> 1
31
- return s.length % 2 ? s[m]! : (s[m - 1]! + s[m]!) / 2
32
- }
33
-
34
- // S0:'!' 边际操作本身(1 次整数 === 比较 + 分支)的解释器成本——FFI 层噪声
35
- // ±400~900ns/call 盖住了 12.5μs 调用上的 ns 级效应,这里绕开 ffiCall 直接量单检查。
36
- // flag 必须是模块级可变量:QuickJS 编译期会常量折叠字面量,折叠掉就测不到了。
37
- let microFlag = true
38
- const MICRO_N = 100_000_000
39
- function microLoop(): number {
40
- const t0 = Date.now()
41
- let hits = 0
42
- for (let i = 0; i < MICRO_N; i++)
43
- if (microFlag && i === 0) hits++
44
- const dt = Date.now() - t0
45
- if (hits !== (microFlag ? 1 : 0)) throw new Error('micro sanity failed: hits=' + hits)
46
- return dt
47
- }
48
- function microSuite(): void {
49
- step('suite: S0 micro 0-check interpreter cost (n=' + String(MICRO_N) + ')')
50
- microFlag = true; microLoop()
51
- microFlag = false; microLoop()
52
- const ts: number[] = []
53
- const fs: number[] = []
54
- for (let r = 0; r < 5; r++) {
55
- // 奇偶交叉起跑顺序(同原 bench 方法)
56
- if (r % 2 === 0) {
57
- microFlag = true; ts.push(microLoop())
58
- microFlag = false; fs.push(microLoop())
59
- } else {
60
- microFlag = false; fs.push(microLoop())
61
- microFlag = true; ts.push(microLoop())
62
- }
63
- step(' round ' + String(r) + ': check=' + String(ts[ts.length - 1]) +
64
- 'ms base=' + String(fs[fs.length - 1]) + 'ms')
65
- }
66
- const ns = (ms: number) => (ms * 1e6 / MICRO_N).toFixed(2)
67
- const tmed = med(ts), fmed = med(fs)
68
- step(' ** median: check=' + ns(tmed) + 'ns/op base=' + ns(fmed) +
69
- 'ns/op ==> per-check cost=' + ((tmed - fmed) * 1e6 / MICRO_N).toFixed(2) + 'ns')
70
- }
71
-
72
- // 文件日志(cwd=Z:\quickwin,宿主机 _build/bench_nonnull_log.txt 可实时读)——exec 只在
73
- // 进程退出后回包,挂了靠它定位卡点
74
- const log = std.open('bench_nonnull_log.txt', 'w')
75
- function step(msg: string): void {
76
- std.printf('%s\n', msg)
77
- if (log) { log.puts(msg + '\n'); log.flush() }
78
- }
79
-
80
- step('stage: imports ok')
81
-
82
- const winRaw = gui.CreateWindow('STATIC', 'bench-title', 0, 0, 0, 20, 20, null, null)
83
- if (!winRaw) throw new Error('CreateWindow(STATIC) failed')
84
- const win: gui.HWND = winRaw
85
- step('stage: window created')
86
-
87
- const SIG = '<HWND>ptr u32 <>ptr <>ptr -> <>ptr'
88
- const fA1 = bind('user32.dll', 'SendMessageW', SIG)
89
- const fA2 = bind('user32.dll', 'SendMessageW', SIG) // A/A 对照:同签名二绑 = 噪声底
90
- const fB = bind('user32.dll', 'SendMessageW', '<HWND>ptr! u32 <>ptr <>ptr -> <>ptr')
91
- const fC = bind('user32.dll', 'SendMessageW', '<HWND>ptr! u32 <>ptr <>ptr -> <>ptr!')
92
-
93
- // 各 BindFn 结构等价 → 收敛到一个可传参的函数型(循环内统一走局部参数,开销对齐)
94
- type SM = (h: gui.HWND, msg: number, w: number, l: number) => number
95
-
96
- const TEXT = 'bench'
97
- const buf = new PtrArrayBuffer<'WCHAR'>(64)
98
-
99
- // C 臂可行性探针:A1 读各场景原始返回值,撞 0 的场景不进 C('!' 会 throw)。
100
- // S1 的 WM_NULL 走 DefWindowProc 预期返 0 → C 不进 S1 是预期而非缺测。
101
- const retS1 = fA1(win, WM_NULL, 0, 0x1234)
102
- const retS2 = fA1(win, WM_SETTEXT, 0, WCHAR.encode(TEXT).ptr)
103
- const retS3 = fA1(win, WM_GETTEXT, 64, buf.ptr)
104
- step('probe ret: S1=' + String(retS1) + ' S2=' + String(retS2) + ' S3=' + String(retS3) +
105
- ' (C arm only enters nonzero scenes)')
106
-
107
- function run1(f: SM): number {
108
- const t0 = Date.now()
109
- for (let i = 0; i < BATCH; i++) f(win, WM_NULL, 0, 0x1234)
110
- return Date.now() - t0
111
- }
112
- function run2(f: SM): number {
113
- const t0 = Date.now()
114
- for (let i = 0; i < N_S2; i++) {
115
- const w = WCHAR.encode(TEXT)
116
- f(win, WM_SETTEXT, 0, w.ptr)
117
- }
118
- return Date.now() - t0
119
- }
120
- function run3(f: SM): number {
121
- const t0 = Date.now()
122
- for (let i = 0; i < BATCH; i++) f(win, WM_GETTEXT, 64, buf.ptr)
123
- return Date.now() - t0
124
- }
125
-
126
- type Arm = { label: string; fn: () => number }
127
-
128
- function suite(name: string, n: number, rounds: number, arms: Arm[]): void {
129
- step('suite: ' + name + ' warmup')
130
- for (const a of arms) a.fn() // 预热各 1 轮
131
- const times: number[][] = arms.map(() => [])
132
- for (let r = 0; r < rounds; r++) {
133
- // 臂序按 r 轮转起跑,抵消顺序性偏置(温度/调度漂移)
134
- for (let k = 0; k < arms.length; k++) {
135
- const i = (r + k) % arms.length
136
- times[i]!.push(arms[i]!.fn())
137
- }
138
- }
139
- // 每轮原始数据只 dump 前 3 轮(30 轮全打没意义,log 只留诊断线索)
140
- for (let r = 0; r < Math.min(rounds, 3); r++) {
141
- step(' round ' + String(r) + ': ' +
142
- arms.map((a, i) => a.label + '=' + String(times[i]![r]) + 'ms').join(' '))
143
- }
144
- const ns = (ms: number) => (ms * 1e6 / n).toFixed(1)
145
- // median 是主指标(离群稳健);min 留作与前两轮/原 bench 的可比项
146
- const meds = times.map(med)
147
- const mins = times.map(t => Math.min(...t))
148
- step(' ** median: ' + arms.map((a, i) =>
149
- a.label + '=' + ns(meds[i]!) + 'ns').join(' | '))
150
- step(' min: ' + arms.map((a, i) =>
151
- a.label + '=' + ns(mins[i]!) + 'ns').join(' | '))
152
- for (let i = 1; i < arms.length; i++)
153
- step(' vs A1: ' + arms[i]!.label + ' delta=' +
154
- ((meds[i]! - meds[0]!) * 1e6 / n).toFixed(1) + 'ns/call (median), ' +
155
- ((mins[i]! - mins[0]!) * 1e6 / n).toFixed(1) + 'ns/call (min)' +
156
- (i === 1 ? ' <-- A2-A1 = NOISE FLOOR' : ''))
157
- }
158
-
159
- const s1Arms: Arm[] = [
160
- { label: 'A1', fn: () => run1(fA1) },
161
- { label: 'A2', fn: () => run1(fA2) },
162
- { label: 'B ', fn: () => run1(fB) },
163
- ]
164
- if (retS1 !== 0) s1Arms.push({ label: 'C ', fn: () => run1(fC) })
165
- const s2Arms: Arm[] = [
166
- { label: 'A1', fn: () => run2(fA1) },
167
- { label: 'A2', fn: () => run2(fA2) },
168
- { label: 'B ', fn: () => run2(fB) },
169
- ]
170
- if (retS2 !== 0) s2Arms.push({ label: 'C ', fn: () => run2(fC) })
171
- const s3Arms: Arm[] = [
172
- { label: 'A1', fn: () => run3(fA1) },
173
- { label: 'A2', fn: () => run3(fA2) },
174
- { label: 'B ', fn: () => run3(fB) },
175
- ]
176
- if (retS3 !== 0) s3Arms.push({ label: 'C ', fn: () => run3(fC) })
177
-
178
- step('bench_sendmessage_nonnull: S1/S3 batch=' + String(BATCH) + '×' + String(ROUNDS) +
179
- 'r, S2 n=' + String(N_S2) + '×' + String(ROUNDS_S2) + 'r (median 主指标)')
180
- microSuite()
181
- suite('S1 WM_NULL 纯数字参数 (最灵敏测点)', BATCH, ROUNDS, s1Arms)
182
- suite('S2 WM_SETTEXT 字符串 lParam (FFI 侧含 WCHAR.encode)', N_S2, ROUNDS_S2, s2Arms)
183
- suite('S3 WM_GETTEXT 缓冲出参往返', BATCH, ROUNDS, s3Arms)
184
-
185
- gui.DestroyWindow(win)
186
- step('DONE')
187
- if (log) log.close()
188
- std.exit(0)
package/test/complex.wasm DELETED
Binary file
Binary file
@@ -1,31 +0,0 @@
1
- import '../../lib/fetch.js';
2
- import { createServer } from '../../lib/http-server.js';
3
- import * as std from 'std';
4
- const server = createServer(async (req) => {
5
- const url = new URL(req.url);
6
- if (url.pathname === '/echo') {
7
- return new Response(JSON.stringify({ method: req.method, path: url.pathname, body: await req.text(), q: Object.fromEntries(url.searchParams) }), { headers: { 'Content-Type': 'application/json' } });
8
- }
9
- return new Response('hello from quickwin http-server', { headers: { 'Content-Type': 'text/plain' } });
10
- });
11
- const rc = server.listen(0, '127.0.0.1');
12
- if (rc !== 0) {
13
- console.log('listen failed');
14
- std.exit(1);
15
- }
16
- const addr = server.address();
17
- const port = addr.port;
18
- console.log('server on port', port);
19
- async function main() {
20
- const r1 = await fetch(`http://127.0.0.1:${port}/`);
21
- console.log('GET / status', r1.status, 'body:', await r1.text());
22
- const r2 = await fetch(`http://127.0.0.1:${port}/echo?x=1`, {
23
- method: 'POST',
24
- headers: { 'Content-Type': 'text/plain' },
25
- body: 'hello-body',
26
- });
27
- console.log('POST /echo status', r2.status, 'body:', await r2.text());
28
- server.close();
29
- std.exit(0);
30
- }
31
- main();
@@ -1,52 +0,0 @@
1
- import * as std from 'std';
2
- std.printf("Hello\n");
3
- function readWasmFile(path) {
4
- const fp = std.open(path, 'rb');
5
- if (!fp) {
6
- return null;
7
- }
8
- fp.seek(0, 2); // SEEK_END
9
- const size = fp.tell();
10
- fp.seek(0, 0); // SEEK_SET
11
- const buffer = new ArrayBuffer(size);
12
- fp.read(buffer, 0, size);
13
- fp.close();
14
- return buffer;
15
- }
16
- const wasmBuf = readWasmFile('./complex_imports.wasm');
17
- try {
18
- if (!wasmBuf)
19
- throw new Error('failed to load wasm');
20
- const m = new WebAssembly.Module(wasmBuf);
21
- console.log('imports:', WebAssembly.Module.imports(m));
22
- console.log('exports:', WebAssembly.Module.exports(m));
23
- const inst = new WebAssembly.Instance(m, {
24
- env: {
25
- log_i32: (x) => { console.log(' log_i32:', x); },
26
- log_i64: (x) => { console.log(' log_i64:', x); },
27
- log_f32: (x) => { console.log(' log_f32:', x); },
28
- log_f64: (x) => { console.log(' log_f64:', x); },
29
- op_i32: (a, b, c) => a * b + c,
30
- }
31
- });
32
- const exp = inst.exports;
33
- console.log('--- i32 ---');
34
- let r = exp.run_i32(7);
35
- console.log(' run_i32(7) =>', r, '(expected 75)');
36
- console.log('--- i64 ---');
37
- r = exp.run_i64(100000, 200000);
38
- console.log(' run_i64(100000, 200000) =>', r, '(expected 300000)');
39
- r = exp.run_i64(10000000000, 20000000000);
40
- console.log(' run_i64(10000000000, 20000000000) =>', r, '(expected 30000000000)');
41
- console.log('--- f32 ---');
42
- r = exp.run_f32(3.5);
43
- console.log(' run_f32(3.5) =>', r, '(expected 7.0)');
44
- console.log('--- f64 ---');
45
- r = exp.run_f64(2.5, 4.0);
46
- console.log(' run_f64(2.5, 4.0) =>', r, '(expected 10.0)');
47
- console.log('--- all done ---');
48
- }
49
- catch (e) {
50
- console.log('ERROR:', e);
51
- }
52
- ;
@@ -1,86 +0,0 @@
1
- import * as std from 'std';
2
- import { MUPDF_JS_URL, preloadMupdfWasm } from '../mupdf-cdn.js';
3
- await preloadMupdfWasm();
4
- await import(MUPDF_JS_URL);
5
- // Debug the instance exports
6
- const inst = globalThis["$wasm_inst"];
7
- const mod = globalThis["$wasm_mod"];
8
- console.log('=== WASM Module exports (first 30) ===');
9
- const modExports = WebAssembly.Module.exports(mod);
10
- for (let i = 0; i < 30 && i < modExports.length; i++)
11
- console.log(` ${i}: ${modExports[i].name} (${modExports[i].kind})`);
12
- // Find Sf and Tf indices
13
- let sf_idx = -1, tf_idx = -1;
14
- for (let i = 0; i < modExports.length; i++) {
15
- if (modExports[i].name === 'Sf')
16
- sf_idx = i;
17
- if (modExports[i].name === 'Tf')
18
- tf_idx = i;
19
- }
20
- console.log('Sf index:', sf_idx, 'Tf index:', tf_idx);
21
- console.log('instance exports Sf:', typeof inst.exports['Sf']);
22
- console.log('instance exports Tf:', typeof inst.exports['Tf']);
23
- // Load a simple WASM to verify bridge works
24
- const fp = std.open('./test/example.pdf', 'rb');
25
- if (!fp) {
26
- console.log('cannot open example.pdf');
27
- std.exit(1);
28
- }
29
- fp.seek(0, 2);
30
- const size = fp.tell();
31
- fp.seek(0, 0);
32
- const buf = new ArrayBuffer(size);
33
- fp.read(buf, 0, size);
34
- fp.close();
35
- console.log('\npdf size:', size);
36
- // Try calling lower-level functions directly
37
- const lib = globalThis["$libmupdf_wasm_Module"];
38
- // First open the document
39
- const wasmMemory = inst.exports['cb'];
40
- console.log('WASM memory:', typeof wasmMemory, wasmMemory?.buffer?.byteLength);
41
- // Create a buffer and try
42
- const bufPtr = lib._wasm_malloc(size);
43
- console.log('malloc buffer pointer:', bufPtr);
44
- // Write PDF data into WASM memory at bufPtr...
45
- const mem8 = new Uint8Array(wasmMemory.buffer);
46
- for (let i = 0; i < size; i++)
47
- mem8[bufPtr + i] = (new Uint8Array(buf))[i];
48
- console.log('wrote pdf data to WASM memory at', bufPtr);
49
- // Try opening document directly with _wasm_open_document_with_buffer
50
- // Need a string for "application/pdf"
51
- const magicStr = "application/pdf\x00";
52
- const magicPtr = lib._wasm_malloc(magicStr.length);
53
- for (let i = 0; i < magicStr.length; i++)
54
- mem8[magicPtr + i] = magicStr.charCodeAt(i);
55
- console.log('magic string at', magicPtr);
56
- // Create a Buffer wrapper object - need to call Buffer constructor
57
- // Actually let's just call the low-level function directly
58
- const fz_ptr = inst.exports['Mf'](magicPtr, bufPtr); // _wasm_open_document_with_buffer
59
- console.log('_wasm_open_document_with_buffer returned:', fz_ptr, typeof fz_ptr);
60
- if (fz_ptr && typeof fz_ptr === 'number') {
61
- // Try countPages
62
- const count = inst.exports['Sf'](fz_ptr);
63
- console.log('_wasm_count_pages returned:', count, typeof count);
64
- // Try loadPage
65
- if (typeof fz_ptr !== 'number') {
66
- console.log('fz_ptr is not a number!');
67
- }
68
- const pagePtr = inst.exports['Tf'](fz_ptr, 0);
69
- console.log('_wasm_load_page returned:', pagePtr, typeof pagePtr);
70
- // Get bounds
71
- // _wasm_bound_page(Sf?) - need to find this export
72
- for (let i = 0; i < modExports.length; i++) {
73
- if (modExports[i].name.startsWith('Uf')) {
74
- console.log('Uf at index', i, '- likely _wasm_pdf_page_from_fz_page');
75
- }
76
- if (modExports[i].name.startsWith('Vf')) {
77
- console.log('Vf at index', i);
78
- }
79
- }
80
- // Try calling _wasm_pdf_page_from_fz_page (Uf)
81
- const pdfPtr = inst.exports['Uf'](pagePtr);
82
- console.log('_wasm_pdf_page_from_fz_page returned:', pdfPtr, typeof pdfPtr);
83
- }
84
- lib._wasm_free(magicPtr);
85
- lib._wasm_free(bufPtr);
86
- console.log('\ndone');
@@ -1,122 +0,0 @@
1
- import * as std from 'std';
2
- function readWasmFile(path) {
3
- const fp = std.open(path, 'rb');
4
- if (!fp)
5
- return null;
6
- fp.seek(0, 2);
7
- const size = fp.tell();
8
- fp.seek(0, 0);
9
- const buffer = new ArrayBuffer(size);
10
- fp.read(buffer, 0, size);
11
- fp.close();
12
- return buffer;
13
- }
14
- var ok = 0, fail = 0;
15
- function check(name, expected, actual) {
16
- if (typeof expected === 'number' && typeof actual === 'number') {
17
- if (Math.abs(expected - actual) < 0.0001) {
18
- ok++;
19
- std.printf(' PASS: %s = %s\n', name, String(actual));
20
- }
21
- else {
22
- fail++;
23
- std.printf(' FAIL: %s = %s (expected %s)\n', name, String(actual), String(expected));
24
- }
25
- }
26
- else if (expected === actual) {
27
- ok++;
28
- std.printf(' PASS: %s = %s\n', name, String(actual));
29
- }
30
- else {
31
- fail++;
32
- std.printf(' FAIL: %s = %s (expected %s)\n', name, String(actual), String(expected));
33
- }
34
- }
35
- std.printf('=== validate ===\n');
36
- check('empty buffer', false, WebAssembly.validate(new Uint8Array([]).buffer));
37
- check('invalid bytes', false, WebAssembly.validate(new Uint8Array([1, 2, 3]).buffer));
38
- const wasmBuffer = readWasmFile('./add.wasm');
39
- if (!wasmBuffer) {
40
- std.printf('FAIL: cannot load add.wasm\n');
41
- std.exit(1);
42
- }
43
- check('valid module', true, WebAssembly.validate(wasmBuffer));
44
- std.printf('=== Module ===\n');
45
- var module = null;
46
- try {
47
- module = new WebAssembly.Module(wasmBuffer);
48
- check('Module constructor', true, module instanceof WebAssembly.Module);
49
- }
50
- catch (e) {
51
- std.printf(' FAIL: Module constructor: %s\n', String(e));
52
- fail++;
53
- }
54
- std.printf('=== Module.exports ===\n');
55
- if (module) {
56
- try {
57
- const exps = WebAssembly.Module.exports(module);
58
- check('exports count', 1, exps.length);
59
- check('export name', 'add', exps[0].name);
60
- check('export kind', 'function', exps[0].kind);
61
- }
62
- catch (e) {
63
- std.printf(' FAIL: Module.exports: %s\n', String(e));
64
- fail++;
65
- }
66
- }
67
- std.printf('=== Instance (add.wasm) ===\n');
68
- if (module) {
69
- try {
70
- const instance = new WebAssembly.Instance(module);
71
- const iExp = instance.exports;
72
- check('Instance created', true, instance instanceof WebAssembly.Instance);
73
- check('add(1, 2)', 3, iExp.add(1, 2));
74
- check('add(10, 20)', 30, iExp.add(10, 20));
75
- check('add(-5, 3)', -2, iExp.add(-5, 3));
76
- }
77
- catch (e) {
78
- std.printf(' FAIL: Instance: %s\n', String(e));
79
- fail++;
80
- }
81
- }
82
- std.printf('=== complex.wasm (multi exports) ===\n');
83
- const complexBuffer = readWasmFile('./complex.wasm');
84
- if (complexBuffer) {
85
- try {
86
- const cmod = new WebAssembly.Module(complexBuffer);
87
- const cinst = new WebAssembly.Instance(cmod);
88
- const cExp = cinst.exports;
89
- check('add(3, 4)', 7, cExp.add(3, 4));
90
- check('sub(10, 3)', 7, cExp.sub(10, 3));
91
- check('mul(6, 7)', 42, cExp.mul(6, 7));
92
- check('factorial(0)', 1, cExp.factorial(0));
93
- check('factorial(5)', 120, cExp.factorial(5));
94
- check('factorial(10)', 3628800, cExp.factorial(10));
95
- }
96
- catch (e) {
97
- std.printf(' FAIL: complex.wasm: %s\n', String(e));
98
- fail++;
99
- }
100
- }
101
- std.printf('=== import function support ===\n');
102
- const importFuncBuffer = readWasmFile('./import_func.wasm');
103
- if (importFuncBuffer) {
104
- try {
105
- const ifmod = new WebAssembly.Module(importFuncBuffer);
106
- const importObject = {
107
- env: { imported_add: (a, b) => a + b }
108
- };
109
- const ifinst = new WebAssembly.Instance(ifmod, importObject);
110
- const ifExp = ifinst.exports;
111
- check('add_via_import(3, 4)', 7, ifExp.add_via_import(3, 4));
112
- check('add_via_import(10, 20)', 30, ifExp.add_via_import(10, 20));
113
- check('add_via_import(-5, 3)', -2, ifExp.add_via_import(-5, 3));
114
- }
115
- catch (e) {
116
- std.printf(' FAIL: import_func.wasm: %s\n', String(e));
117
- fail++;
118
- }
119
- }
120
- std.printf('\n%d/%d tests passed\n', ok, ok + fail);
121
- if (fail > 0)
122
- std.exit(1);
@@ -1,54 +0,0 @@
1
- import { fetchMupdfWasm } from '../mupdf-cdn.js';
2
- const buf = await fetchMupdfWasm();
3
- const module = new WebAssembly.Module(buf);
4
- const exports = WebAssembly.Module.exports(module);
5
- const imports = WebAssembly.Module.imports(module);
6
- // List ALL export names
7
- console.log(`=== All exports (${exports.length}) ===`);
8
- for (let i = 0; i < exports.length; i++) {
9
- if (exports[i].name === 'ul' || exports[i].name === 'tl')
10
- console.log(` ${i}: ${exports[i].name} (${exports[i].kind}) *** FOUND ***`);
11
- }
12
- // Check last 20 exports
13
- console.log(`\n=== Last 20 exports ===`);
14
- for (let i = Math.max(0, exports.length - 20); i < exports.length; i++)
15
- console.log(` ${i}: ${exports[i].name} (${exports[i].kind})`);
16
- // Check if ul/tl are import functions
17
- console.log(`\n=== Imports (${imports.length}) ===`);
18
- for (let i = 0; i < imports.length; i++) {
19
- if (imports[i].name === 'ul' || imports[i].name === 'tl')
20
- console.log(` ${i}: ${imports[i].module}.${imports[i].name}`);
21
- }
22
- // Now try to call simple exports and see if exec_env is the issue
23
- console.log(`\n=== Direct instance call test ===`);
24
- const importObj = { a: {} };
25
- for (const imp of imports) {
26
- if (!importObj[imp.module])
27
- importObj[imp.module] = {};
28
- if (imp.kind === 'function') {
29
- importObj[imp.module][imp.name] = () => 0;
30
- }
31
- }
32
- // Test calling db, eb sequentially
33
- const inst = new WebAssembly.Instance(module, importObj);
34
- const exp = inst.exports;
35
- console.log('1. calling db()...');
36
- exp['db']();
37
- console.log('2. calling db() again...');
38
- exp['db']();
39
- console.log('3. calling eb()...');
40
- try {
41
- exp['eb']();
42
- console.log(' eb() succeeded');
43
- }
44
- catch (e) {
45
- console.log(' eb() failed:', e);
46
- }
47
- console.log('4. calling fb(100)...');
48
- try {
49
- const r = exp['fb'](100);
50
- console.log(' fb(100) =', r);
51
- }
52
- catch (e) {
53
- console.log(' fb(100) failed:', e);
54
- }
@@ -1,36 +0,0 @@
1
- import { fetchMupdfWasm } from '../mupdf-cdn.js';
2
- // Fetch the mupdf-wasm binary over HTTPS (process-wide HTTP cache applies)
3
- const buf = await fetchMupdfWasm();
4
- // Check exports for Tf
5
- const module = new WebAssembly.Module(buf);
6
- const exports = WebAssembly.Module.exports(module);
7
- const imports = WebAssembly.Module.imports(module);
8
- // Look for Tf specifically
9
- let foundTf = false;
10
- for (const e of exports) {
11
- if (e.name === 'Tf') {
12
- console.log('FOUND Tf in exports');
13
- foundTf = true;
14
- break;
15
- }
16
- }
17
- if (!foundTf)
18
- console.log('Tf NOT in exports');
19
- // Check a few nearby names used in assignWasmExports
20
- const wanted = ['Tf', 'Uf', 'Vf', 'Wf', 'Xf', 'Yf', 'Sf', 'Rf', 'Qf', 'Pf', 'Of', 'Nf'];
21
- const found = [];
22
- const missing = [];
23
- for (const w of wanted) {
24
- if (exports.some(e => e.name === w))
25
- found.push(w);
26
- else
27
- missing.push(w);
28
- }
29
- console.log('found:', found.join(', '));
30
- console.log('missing:', missing.join(', '));
31
- // Count exports
32
- console.log('total exports:', exports.length);
33
- console.log('total imports:', imports.length);
34
- // List first 30 export names
35
- for (let i = 0; i < 30 && i < exports.length; i++)
36
- console.log(' export', i, '=', exports[i].name);
package/test/example.pdf DELETED
Binary file
Binary file
Binary file
package/test/imports.wasm DELETED
Binary file
package/test/mupdf-cdn.js DELETED
@@ -1,40 +0,0 @@
1
- // ── mupdf-wasm CDN loading ──
2
- //
3
- // The runtime loads mupdf from unpkg; the npm package itself only ships
4
- // types (devDependency @quickwinlabs/mupdf-wasm resolved through the
5
- // package's exports types mapping — no local vendor copy involved).
6
- // MUPDF_VERSION must stay in sync with the devDependency in package.json
7
- // when bumping.
8
- //
9
- // Importing this module wires up the HTTPS stack (certs + fetch): the
10
- // wasm bytes travel through the process-wide HTTP cache next to the
11
- // executable, so the first fetch is the only network hit.
12
- import '../lib/certs.js';
13
- import '../lib/fetch.js';
14
- export const MUPDF_VERSION = '1.28.0';
15
- const BASE = `https://unpkg.com/@quickwinlabs/mupdf-wasm@${MUPDF_VERSION}`;
16
- export const MUPDF_JS_URL = `${BASE}/mupdf.js`;
17
- export const MUPDF_WASM_URL = `${BASE}/mupdf-wasm.wasm`;
18
- /** Fetch the wasm binary over HTTPS (HTTP-cached, no filesystem involved). */
19
- export async function fetchMupdfWasm() {
20
- const resp = await fetch(MUPDF_WASM_URL);
21
- if (resp.status !== 200)
22
- throw new Error(`mupdf wasm fetch failed: HTTP ${resp.status}`);
23
- const wasmBinary = await resp.arrayBuffer();
24
- if (wasmBinary.byteLength < 1_000_000)
25
- throw new Error(`mupdf wasm truncated: ${wasmBinary.byteLength} bytes`);
26
- return wasmBinary;
27
- }
28
- /**
29
- * Fetch the wasm binary and pre-wire it as $libmupdf_wasm_Module so the
30
- * mupdf.js module factory instantiates from memory (same injection the
31
- * local-vendor loading used).
32
- */
33
- export async function preloadMupdfWasm() {
34
- const wasmBinary = await fetchMupdfWasm();
35
- globalThis.$libmupdf_wasm_Module = {
36
- wasmBinary,
37
- locateFile: (p) => p,
38
- };
39
- return wasmBinary;
40
- }
package/test/mupdf-cdn.ts DELETED
@@ -1,43 +0,0 @@
1
- // ── mupdf-wasm CDN loading ──
2
- //
3
- // The runtime loads mupdf from unpkg; the npm package itself only ships
4
- // types (devDependency @quickwinlabs/mupdf-wasm resolved through the
5
- // package's exports types mapping — no local vendor copy involved).
6
- // MUPDF_VERSION must stay in sync with the devDependency in package.json
7
- // when bumping.
8
- //
9
- // Importing this module wires up the HTTPS stack (certs + fetch): the
10
- // wasm bytes travel through the process-wide HTTP cache next to the
11
- // executable, so the first fetch is the only network hit.
12
-
13
- import '../lib/certs.js'
14
- import '../lib/fetch.js'
15
-
16
- export const MUPDF_VERSION = '1.28.0'
17
- const BASE = `https://unpkg.com/@quickwinlabs/mupdf-wasm@${MUPDF_VERSION}`
18
-
19
- export const MUPDF_JS_URL = `${BASE}/mupdf.js`
20
- export const MUPDF_WASM_URL = `${BASE}/mupdf-wasm.wasm`
21
-
22
- /** Fetch the wasm binary over HTTPS (HTTP-cached, no filesystem involved). */
23
- export async function fetchMupdfWasm(): Promise<ArrayBuffer> {
24
- const resp = await fetch(MUPDF_WASM_URL)
25
- if (resp.status !== 200) throw new Error(`mupdf wasm fetch failed: HTTP ${resp.status}`)
26
- const wasmBinary = await resp.arrayBuffer()
27
- if (wasmBinary.byteLength < 1_000_000) throw new Error(`mupdf wasm truncated: ${wasmBinary.byteLength} bytes`)
28
- return wasmBinary
29
- }
30
-
31
- /**
32
- * Fetch the wasm binary and pre-wire it as $libmupdf_wasm_Module so the
33
- * mupdf.js module factory instantiates from memory (same injection the
34
- * local-vendor loading used).
35
- */
36
- export async function preloadMupdfWasm(): Promise<ArrayBuffer> {
37
- const wasmBinary = await fetchMupdfWasm()
38
- ;(globalThis as any).$libmupdf_wasm_Module = {
39
- wasmBinary,
40
- locateFile: (p: string) => p,
41
- }
42
- return wasmBinary
43
- }