utils.scm 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. ;;; Copyright (C) 2023, 2024, 2025 Igalia, S.L.
  2. ;;;
  3. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  4. ;;; you may not use this file except in compliance with the License.
  5. ;;; You may obtain a copy of the License at
  6. ;;;
  7. ;;; http://www.apache.org/licenses/LICENSE-2.0
  8. ;;;
  9. ;;; Unless required by applicable law or agreed to in writing, software
  10. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  11. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. ;;; See the License for the specific language governing permissions and
  13. ;;; limitations under the License.
  14. ;;; Commentary:
  15. ;;;
  16. ;;; Test utilities.
  17. ;;;
  18. ;;; Code:
  19. (define-module (test utils)
  20. #:use-module (wasm assemble)
  21. #:use-module (wasm parse)
  22. #:use-module (hoot config)
  23. #:use-module (hoot compile)
  24. #:use-module (hoot reflect)
  25. #:use-module (ice-9 binary-ports)
  26. #:use-module (ice-9 match)
  27. #:use-module (ice-9 popen)
  28. #:use-module (ice-9 textual-ports)
  29. #:use-module (srfi srfi-64)
  30. #:use-module ((system syntax) #:select (syntax?))
  31. #:export (use-node?
  32. use-d8?
  33. use-hoot-vm?
  34. v8
  35. unwind-protect
  36. call-with-compiled-wasm-file
  37. compile-main
  38. compile-aux
  39. load-wasm
  40. call-wasm
  41. await-call-wasm
  42. test-compilation
  43. test-call
  44. test-await
  45. test-end*
  46. with-imports
  47. with-additional-imports))
  48. (define test-hosts (string-split (or (getenv "WASM_HOST") "node,hoot") #\,))
  49. (define use-d8? (make-parameter (member "d8" test-hosts)))
  50. (define use-node? (make-parameter (member "node" test-hosts)))
  51. (define use-hoot-vm? (make-parameter (member "hoot" test-hosts)))
  52. (define (unwind-protect body unwind)
  53. (call-with-values
  54. (lambda ()
  55. (with-exception-handler
  56. (lambda (exn)
  57. (unwind)
  58. (raise-exception exn))
  59. body))
  60. (lambda vals
  61. (unwind)
  62. (apply values vals))))
  63. (define (call-with-compiled-wasm-file wasm f)
  64. (let* ((wasm-port (mkstemp "/tmp/tmp-wasm-XXXXXX"))
  65. (wasm-file-name (port-filename wasm-port)))
  66. (put-bytevector wasm-port (assemble-wasm wasm))
  67. (close-port wasm-port)
  68. (unwind-protect
  69. (lambda () (f wasm-file-name))
  70. (lambda () (delete-file wasm-file-name)))))
  71. (define (v8)
  72. (or (and (use-node?) %node)
  73. (and (use-d8?) %d8)
  74. (error "no V8 runtime available")))
  75. (define (run-v8 . args)
  76. (let* ((port (apply open-pipe* OPEN_READ (v8) args))
  77. (output (get-string-all port)))
  78. (close-port port)
  79. (string-trim-both output)))
  80. (define (load-wasm/v8 wasm)
  81. (define runner (in-vicinity %js-runner-dir "load.js"))
  82. (call-with-compiled-wasm-file
  83. wasm
  84. (lambda (wasm-file-name)
  85. (run-v8 runner "--" %reflect-js-dir %reflect-wasm-dir
  86. wasm-file-name))))
  87. (define (apply-wasm/v8 proc args)
  88. (define runner (in-vicinity %js-runner-dir "call.js"))
  89. (let lp ((modules (cons proc args)) (files '()) (first? #t))
  90. (match modules
  91. (()
  92. (apply run-v8 runner "--" %reflect-js-dir %reflect-wasm-dir
  93. (reverse files)))
  94. ((module . rest)
  95. (call-with-compiled-wasm-file
  96. module
  97. (lambda (file)
  98. (lp rest (cons file files) #f)))))))
  99. (define (await-apply-wasm/v8 proc args)
  100. (define runner (in-vicinity %js-runner-dir "await-call.js"))
  101. (let lp ((modules (cons proc args)) (files '()) (first? #t))
  102. (match modules
  103. (()
  104. (apply run-v8 runner "--" %reflect-js-dir %reflect-wasm-dir
  105. (reverse files)))
  106. ((module . rest)
  107. (call-with-compiled-wasm-file
  108. module
  109. (lambda (file)
  110. (lp rest (cons file files) #f)))))))
  111. (define (call-with-printed-values thunk)
  112. (string-trim-both
  113. (with-output-to-string
  114. (lambda ()
  115. (call-with-values thunk
  116. (lambda vals
  117. (for-each (lambda (x)
  118. (hoot-print x (current-output-port))
  119. (newline))
  120. vals)))))))
  121. (define (load-wasm/hoot wasm)
  122. (call-with-printed-values
  123. (lambda ()
  124. (hoot-load (hoot-instantiate wasm)))))
  125. (define (apply-wasm*/hoot proc proc-wasm args-wasm)
  126. (call-with-printed-values
  127. (lambda ()
  128. (let* ((proc-module (hoot-instantiate proc-wasm))
  129. (proc* (hoot-load proc-module))
  130. (reflector (hoot-module-reflector proc-module))
  131. (args (map (lambda (arg)
  132. (hoot-load
  133. (hoot-instantiate arg '() reflector)))
  134. args-wasm)))
  135. (apply proc proc* args)))))
  136. (define (apply-wasm/hoot proc args)
  137. (apply-wasm*/hoot hoot-apply proc args))
  138. (define (await-apply-wasm/hoot proc args)
  139. (apply-wasm*/hoot hoot-apply-async proc args))
  140. (define (compare-results hoot-result v8-result)
  141. (cond
  142. ((and (use-hoot-vm?) (or (use-node?) (use-d8?)))
  143. (unless (equal? hoot-result v8-result)
  144. (error "our result differs from v8" hoot-result v8-result))
  145. hoot-result)
  146. ((or (use-node?) (use-d8?)) v8-result)
  147. (else hoot-result)))
  148. (define-syntax-rule (hoot&v8 hoot-expr v8-expr)
  149. (compare-results (and (use-hoot-vm?) hoot-expr)
  150. (and (or (use-node?) (use-d8?)) v8-expr)))
  151. (define %imports (make-parameter '((scheme base))))
  152. (define (imports-for-expr expr)
  153. ;; In the test suite we sometimes compile datums; don't load any
  154. ;; imports in that case.
  155. (match (if (syntax? expr)
  156. (syntax->datum expr)
  157. expr)
  158. (('quote _) '((hoot syntax)))
  159. ((? self-evaluating?) '())
  160. (else (%imports))))
  161. (define cache (make-hash-table))
  162. (define (compile/cache expr . args)
  163. (cond
  164. ((hash-ref cache (cons expr args)))
  165. (else
  166. (let ((result (apply compile expr #:imports (imports-for-expr expr) args)))
  167. (hash-set! cache (cons expr args) result)
  168. result))))
  169. (define (compile-main expr)
  170. (compile/cache expr))
  171. (define (compile-aux expr)
  172. (compile/cache expr #:import-abi? #t #:export-abi? #f))
  173. (define (load-wasm wasm)
  174. (hoot&v8 (load-wasm/hoot wasm)
  175. (load-wasm/v8 wasm)))
  176. (define (apply-wasm proc args)
  177. (hoot&v8 (apply-wasm/hoot proc args)
  178. (apply-wasm/v8 proc args)))
  179. (define (call-wasm proc . args)
  180. (apply-wasm proc args))
  181. (define (await-apply-wasm proc args)
  182. (hoot&v8 (await-apply-wasm/hoot proc args)
  183. (await-apply-wasm/v8 proc args)))
  184. (define (await-call-wasm proc . args)
  185. (await-apply-wasm proc args))
  186. (define-syntax-rule (test-compilation expr repr)
  187. (test-equal repr repr
  188. (load-wasm (compile-main `expr))))
  189. (define-syntax-rule (test-call repr proc arg ...)
  190. (test-equal repr repr
  191. (call-wasm (compile-main `proc) (compile-aux `arg) ...)))
  192. (define-syntax-rule (test-await repr . body)
  193. (with-additional-imports ((fibers promises))
  194. (test-equal repr repr
  195. (await-call-wasm
  196. (compile-main
  197. `(lambda (resolved rejected)
  198. (call-with-async-result
  199. resolved rejected (lambda () . body))))))))
  200. (define-syntax-rule (test-end* name)
  201. (begin
  202. (when (and (batch-mode?)
  203. (or (not (zero? (test-runner-fail-count (test-runner-get))))
  204. (not (zero? (test-runner-xpass-count (test-runner-get))))))
  205. (force-output)
  206. (exit 1))
  207. (test-end name)))
  208. (define-syntax-rule (with-imports (ispec ...) . body)
  209. (parameterize ((%imports '(ispec ...)))
  210. . body))
  211. (define-syntax-rule (with-additional-imports (ispec ...) . body)
  212. (parameterize ((%imports (cons* 'ispec ... (%imports))))
  213. . body))