utils.scm 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. ;;; Copyright (C) 2023, 2024 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. #:export (use-node?
  31. use-d8?
  32. use-hoot-vm?
  33. v8
  34. unwind-protect
  35. call-with-compiled-wasm-file
  36. compile-main
  37. compile-aux
  38. load-wasm
  39. call-wasm
  40. await-call-wasm
  41. test-compilation
  42. test-call
  43. test-await
  44. test-end*
  45. with-imports
  46. with-additional-imports))
  47. (define test-hosts (string-split (or (getenv "WASM_HOST") "node,hoot") #\,))
  48. (define use-d8? (make-parameter (member "d8" test-hosts)))
  49. (define use-node? (make-parameter (member "node" test-hosts)))
  50. (define use-hoot-vm? (make-parameter (member "hoot" test-hosts)))
  51. (define (unwind-protect body unwind)
  52. (call-with-values
  53. (lambda ()
  54. (with-exception-handler
  55. (lambda (exn)
  56. (unwind)
  57. (raise-exception exn))
  58. body))
  59. (lambda vals
  60. (unwind)
  61. (apply values vals))))
  62. (define (call-with-compiled-wasm-file wasm f)
  63. (let* ((wasm-port (mkstemp "/tmp/tmp-wasm-XXXXXX"))
  64. (wasm-file-name (port-filename wasm-port)))
  65. (put-bytevector wasm-port (assemble-wasm wasm))
  66. (close-port wasm-port)
  67. (unwind-protect
  68. (lambda () (f wasm-file-name))
  69. (lambda () (delete-file wasm-file-name)))))
  70. (define (v8)
  71. (or (and (use-node?) %node)
  72. (and (use-d8?) %d8)
  73. (error "no V8 runtime available")))
  74. (define (run-v8 . args)
  75. (let* ((port (apply open-pipe* OPEN_READ (v8) args))
  76. (output (get-string-all port)))
  77. (close-port port)
  78. (string-trim-both output)))
  79. (define (load-wasm/v8 wasm)
  80. (define runner (in-vicinity %js-runner-dir "load.js"))
  81. (call-with-compiled-wasm-file
  82. wasm
  83. (lambda (wasm-file-name)
  84. (run-v8 runner "--" %reflect-js-dir %reflect-wasm-dir
  85. wasm-file-name))))
  86. (define (apply-wasm/v8 proc args)
  87. (define runner (in-vicinity %js-runner-dir "call.js"))
  88. (let lp ((modules (cons proc args)) (files '()) (first? #t))
  89. (match modules
  90. (()
  91. (apply run-v8 runner "--" %reflect-js-dir %reflect-wasm-dir
  92. (reverse files)))
  93. ((module . rest)
  94. (call-with-compiled-wasm-file
  95. module
  96. (lambda (file)
  97. (lp rest (cons file files) #f)))))))
  98. (define (await-apply-wasm/v8 proc args)
  99. (define runner (in-vicinity %js-runner-dir "await-call.js"))
  100. (let lp ((modules (cons proc args)) (files '()) (first? #t))
  101. (match modules
  102. (()
  103. (apply run-v8 runner "--" %reflect-js-dir %reflect-wasm-dir
  104. (reverse files)))
  105. ((module . rest)
  106. (call-with-compiled-wasm-file
  107. module
  108. (lambda (file)
  109. (lp rest (cons file files) #f)))))))
  110. (define (call-with-printed-values thunk)
  111. (string-trim-both
  112. (with-output-to-string
  113. (lambda ()
  114. (call-with-values thunk
  115. (lambda vals
  116. (for-each (lambda (x)
  117. (hoot-print x (current-output-port))
  118. (newline))
  119. vals)))))))
  120. (define (load-wasm/hoot wasm)
  121. (call-with-printed-values
  122. (lambda ()
  123. (hoot-load (hoot-instantiate wasm)))))
  124. (define (apply-wasm*/hoot proc proc-wasm args-wasm)
  125. (call-with-printed-values
  126. (lambda ()
  127. (let* ((proc-module (hoot-instantiate proc-wasm))
  128. (proc* (hoot-load proc-module))
  129. (reflector (hoot-module-reflector proc-module))
  130. (args (map (lambda (arg)
  131. (hoot-load
  132. (hoot-instantiate arg '() reflector)))
  133. args-wasm)))
  134. (apply proc proc* args)))))
  135. (define (apply-wasm/hoot proc args)
  136. (apply-wasm*/hoot hoot-apply proc args))
  137. (define (await-apply-wasm/hoot proc args)
  138. (apply-wasm*/hoot hoot-apply-async proc args))
  139. (define (compare-results hoot-result v8-result)
  140. (cond
  141. ((and (use-hoot-vm?) (or (use-node?) (use-d8?)))
  142. (unless (equal? hoot-result v8-result)
  143. (error "our result differs from v8" hoot-result v8-result))
  144. hoot-result)
  145. ((use-d8?) v8-result)
  146. (else hoot-result)))
  147. (define-syntax-rule (hoot&v8 hoot-expr v8-expr)
  148. (compare-results (and (use-hoot-vm?) hoot-expr)
  149. (and (or (use-node?) (use-d8?)) v8-expr)))
  150. (define %imports (make-parameter %default-program-imports))
  151. (define cache (make-hash-table))
  152. (define (compile/cache expr . args)
  153. (cond
  154. ((hash-ref cache (cons expr args)))
  155. (else
  156. (let ((result (apply compile expr #:imports (%imports) args)))
  157. (hash-set! cache (cons expr args) result)
  158. result))))
  159. (define (compile-main expr)
  160. (compile/cache expr))
  161. (define (compile-aux expr)
  162. (compile/cache expr #:import-abi? #t #:export-abi? #f))
  163. (define (load-wasm wasm)
  164. (hoot&v8 (load-wasm/hoot wasm)
  165. (load-wasm/v8 wasm)))
  166. (define (apply-wasm proc args)
  167. (hoot&v8 (apply-wasm/hoot proc args)
  168. (apply-wasm/v8 proc args)))
  169. (define (call-wasm proc . args)
  170. (apply-wasm proc args))
  171. (define (await-apply-wasm proc args)
  172. (hoot&v8 (await-apply-wasm/hoot proc args)
  173. (await-apply-wasm/v8 proc args)))
  174. (define (await-call-wasm proc . args)
  175. (await-apply-wasm proc args))
  176. (define-syntax-rule (test-compilation expr repr)
  177. (test-equal repr repr
  178. (load-wasm (compile-main `expr))))
  179. (define-syntax-rule (test-call repr proc arg ...)
  180. (test-equal repr repr
  181. (call-wasm (compile-main `proc) (compile-aux `arg) ...)))
  182. (define-syntax-rule (test-await repr . body)
  183. (with-additional-imports ((fibers promises))
  184. (test-equal repr repr
  185. (await-call-wasm
  186. (compile-main
  187. `(lambda (resolved rejected)
  188. (call-with-async-result
  189. resolved rejected (lambda () . body))))))))
  190. (define-syntax-rule (test-end* name)
  191. (begin
  192. (when (and (batch-mode?)
  193. (or (not (zero? (test-runner-fail-count (test-runner-get))))
  194. (not (zero? (test-runner-xpass-count (test-runner-get))))))
  195. (force-output)
  196. (exit 1))
  197. (test-end name)))
  198. (define-syntax-rule (with-imports (ispec ...) . body)
  199. (parameterize ((%imports '(ispec ...)))
  200. . body))
  201. (define-syntax-rule (with-additional-imports (ispec ...) . body)
  202. (parameterize ((%imports (cons* 'ispec ... (%imports))))
  203. . body))