utils.scm 6.9 KB

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