frame.scm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. ;;; Guile VM frame functions
  2. ;;; Copyright (C) 2001, 2005, 2009-2016 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software; you can redistribute it and/or
  5. ;;; modify it under the terms of the GNU Lesser General Public
  6. ;;; License as published by the Free Software Foundation; either
  7. ;;; version 3 of the License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful,
  10. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this library; if not, write to the Free Software
  16. ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;; Code:
  18. (define-module (system vm frame)
  19. #:use-module (system base pmatch)
  20. #:use-module (system foreign)
  21. #:use-module (system vm program)
  22. #:use-module (system vm debug)
  23. #:use-module (system vm disassembler)
  24. #:use-module (srfi srfi-9)
  25. #:use-module (srfi srfi-11)
  26. #:use-module (rnrs bytevectors)
  27. #:use-module (ice-9 match)
  28. #:export (binding-index
  29. binding-name
  30. binding-slot
  31. binding-representation
  32. frame-bindings
  33. frame-lookup-binding
  34. binding-ref binding-set!
  35. frame-instruction-pointer-or-primitive-procedure-name
  36. frame-call-representation
  37. frame-environment
  38. frame-object-binding frame-object-name))
  39. (eval-when (expand compile load eval)
  40. (load-extension (string-append "libguile-" (effective-version))
  41. "scm_init_frames_builtins"))
  42. (define-record-type <binding>
  43. (make-binding frame idx name slot representation)
  44. binding?
  45. (frame binding-frame)
  46. (idx binding-index)
  47. (name binding-name)
  48. (slot binding-slot)
  49. (representation binding-representation))
  50. (define (parse-code code)
  51. (let ((len (bytevector-length code)))
  52. (let lp ((pos 0) (out '()))
  53. (cond
  54. ((< pos len)
  55. (let* ((inst-len (instruction-length code pos))
  56. (pos (+ pos inst-len)))
  57. (unless (<= pos len)
  58. (error "Failed to parse codestream"))
  59. (lp pos (cons inst-len out))))
  60. (else
  61. (list->vector (reverse out)))))))
  62. (define (compute-predecessors code parsed)
  63. (let ((preds (make-vector (vector-length parsed) '())))
  64. (define (add-pred! from target)
  65. (let lp ((to from) (target target))
  66. (cond
  67. ((negative? target)
  68. (lp (1- to) (+ target (vector-ref parsed (1- to)))))
  69. ((positive? target)
  70. (lp (1+ to) (- target (vector-ref parsed to))))
  71. ((= to (vector-length preds))
  72. ;; This can happen when an arity fails to match. Just ignore
  73. ;; this case.
  74. #t)
  75. (else
  76. (vector-set! preds to (cons from (vector-ref preds to)))))))
  77. (let lp ((n 0) (pos 0))
  78. (when (< n (vector-length preds))
  79. (when (instruction-has-fallthrough? code pos)
  80. (add-pred! n (vector-ref parsed n)))
  81. (for-each (lambda (target)
  82. (add-pred! n target))
  83. (instruction-relative-jump-targets code pos))
  84. (lp (1+ n) (+ pos (vector-ref parsed n)))))
  85. preds))
  86. (define (compute-frame-sizes code parsed initial-size)
  87. (let ((in-sizes (make-vector (vector-length parsed) #f))
  88. (out-sizes (make-vector (vector-length parsed) #f)))
  89. ;; This only computes all possible valid stack sizes if the bytecode
  90. ;; is sorted topologically. Guiles' compiler does this currently,
  91. ;; but if that changes we should do a proper pre-order visit. Of
  92. ;; course the bytecode has to be valid too.
  93. (define (find-idx n diff)
  94. (let lp ((n n) (diff diff))
  95. (cond
  96. ((negative? diff)
  97. (lp (1- n) (+ diff (vector-ref parsed (1- n)))))
  98. ((positive? diff)
  99. (lp (1+ n) (- diff (vector-ref parsed n))))
  100. (else n))))
  101. (vector-set! in-sizes 0 initial-size)
  102. (let lp ((n 0) (pos 0))
  103. (define (offset->idx target)
  104. (call-with-values (lambda ()
  105. (if (>= target pos)
  106. (values n pos)
  107. (values 0 0)))
  108. (lambda (n pos)
  109. (let lp ((n n) (pos pos))
  110. (cond
  111. ((= pos target) n)
  112. ((< pos target) (lp (1+ n) (+ pos (vector-ref parsed n))))
  113. (else (error "bad target" target)))))))
  114. (when (< n (vector-length parsed))
  115. (let* ((in (vector-ref in-sizes n))
  116. (out (instruction-stack-size-after code pos in)))
  117. (vector-set! out-sizes n out)
  118. (when out
  119. (when (instruction-has-fallthrough? code pos)
  120. (vector-set! in-sizes (1+ n) out))
  121. (for-each (lambda (target)
  122. (let ((idx (find-idx n target)))
  123. (when idx
  124. (vector-set! in-sizes idx out))))
  125. (instruction-relative-jump-targets code pos))))
  126. (lp (1+ n) (+ pos (vector-ref parsed n)))))
  127. (values in-sizes out-sizes)))
  128. (define (compute-genv parsed defs)
  129. (let ((genv (make-vector (vector-length parsed) '())))
  130. (define (add-def! pos var)
  131. (vector-set! genv pos (cons var (vector-ref genv pos))))
  132. (let lp ((var 0) (pos 0) (pc-offset 0))
  133. (when (< var (vector-length defs))
  134. (match (vector-ref defs var)
  135. (#(name offset slot representation)
  136. (when (< offset pc-offset)
  137. (error "mismatch between def offsets and parsed code"))
  138. (cond
  139. ((< pc-offset offset)
  140. (lp var (1+ pos) (+ pc-offset (vector-ref parsed pos))))
  141. (else
  142. (add-def! pos var)
  143. (lp (1+ var) pos pc-offset)))))))
  144. genv))
  145. (define (compute-defs-by-slot defs)
  146. (let* ((nslots (match defs
  147. (#(#(_ _ slot _) ...) (1+ (apply max slot)))))
  148. (by-slot (make-vector nslots #f)))
  149. (let lp ((n 0))
  150. (when (< n nslots)
  151. (vector-set! by-slot n (make-bitvector (vector-length defs) #f))
  152. (lp (1+ n))))
  153. (let lp ((n 0))
  154. (when (< n (vector-length defs))
  155. (match (vector-ref defs n)
  156. (#(_ _ slot _)
  157. (bitvector-set! (vector-ref by-slot slot) n #t)
  158. (lp (1+ n))))))
  159. by-slot))
  160. (define (compute-killv code parsed defs)
  161. (let*-values (((defs-by-slot) (compute-defs-by-slot defs))
  162. ((initial-frame-size) (vector-length defs-by-slot))
  163. ((in-sizes out-sizes)
  164. (compute-frame-sizes code parsed initial-frame-size))
  165. ((killv) (make-vector (vector-length parsed) #f)))
  166. (define (kill-slot! n slot)
  167. (bit-set*! (vector-ref killv n) (vector-ref defs-by-slot slot) #t))
  168. (let lp ((n 0))
  169. (when (< n (vector-length killv))
  170. (vector-set! killv n (make-bitvector (vector-length defs) #f))
  171. (lp (1+ n))))
  172. ;; Some defs get into place without explicit instructions -- this is
  173. ;; the case if no shuffling need occur, for example. In any case,
  174. ;; mark them as killing any previous definitions at that slot.
  175. (let lp ((var 0) (pos 0) (pc-offset 0))
  176. (when (< var (vector-length defs))
  177. (match (vector-ref defs var)
  178. (#(name offset slot representation)
  179. (when (< offset pc-offset)
  180. (error "mismatch between def offsets and parsed code"))
  181. (cond
  182. ((< pc-offset offset)
  183. (lp var (1+ pos) (+ pc-offset (vector-ref parsed pos))))
  184. (else
  185. (kill-slot! pos slot)
  186. (lp (1+ var) pos pc-offset)))))))
  187. (let lp ((n 0) (pos 0))
  188. (when (< n (vector-length parsed))
  189. (for-each (lambda (slot)
  190. (when (< slot (vector-length defs-by-slot))
  191. (kill-slot! n slot)))
  192. (instruction-slot-clobbers code pos
  193. (vector-ref in-sizes n)
  194. (vector-ref out-sizes n)))
  195. (lp (1+ n) (+ pos (vector-ref parsed n)))))
  196. killv))
  197. (define (available-bindings frame arity ip top-frame?)
  198. (let* ((defs (list->vector (arity-definitions arity)))
  199. (code (arity-code arity))
  200. (parsed (parse-code code))
  201. (len (vector-length parsed))
  202. (preds (compute-predecessors code parsed))
  203. (genv (compute-genv parsed defs))
  204. (killv (compute-killv code parsed defs))
  205. (inv (make-vector len #f))
  206. (outv (make-vector len #f))
  207. (tmp (make-bitvector (vector-length defs) #f)))
  208. (define (bitvector-copy! dst src)
  209. (bitvector-fill! dst #f)
  210. (bit-set*! dst src #t))
  211. (define (bitvector-meet! accum src)
  212. (bitvector-copy! tmp src)
  213. (bit-invert! tmp)
  214. (bit-set*! accum tmp #f))
  215. (let lp ((n 0))
  216. (when (< n len)
  217. (vector-set! inv n (make-bitvector (vector-length defs) #f))
  218. (vector-set! outv n (make-bitvector (vector-length defs) #f))
  219. (lp (1+ n))))
  220. (let lp ((n 0) (first? #t) (changed? #f))
  221. (cond
  222. ((< n len)
  223. (let ((in (vector-ref inv n))
  224. (out (vector-ref outv n))
  225. (kill (vector-ref killv n))
  226. (gen (vector-ref genv n)))
  227. (let ((out-count (or changed? (bit-count #t out))))
  228. (bitvector-fill! in (not (zero? n)))
  229. (let lp ((preds (vector-ref preds n)))
  230. (match preds
  231. (() #t)
  232. ((pred . preds)
  233. (unless (and first? (<= n pred))
  234. (bitvector-meet! in (vector-ref outv pred)))
  235. (lp preds))))
  236. (bitvector-copy! out in)
  237. (bit-set*! out kill #f)
  238. (for-each (lambda (def)
  239. (bitvector-set! out def #t))
  240. gen)
  241. (lp (1+ n) first?
  242. (or changed? (not (eqv? out-count (bit-count #t out))))))))
  243. ((or changed? first?)
  244. (lp 0 #f #f))))
  245. (let lp ((n 0) (offset (- ip (arity-low-pc arity))))
  246. (when (< offset 0)
  247. (error "ip did not correspond to an instruction boundary?"))
  248. (if (zero? offset)
  249. ;; It shouldn't be the case that both OFFSET and N are zero
  250. ;; but TOP-FRAME? is false. Still, it could happen, as is
  251. ;; currently the case in frame-arguments.
  252. (let ((live (if (or top-frame? (zero? n))
  253. (vector-ref inv n)
  254. ;; If we're not at a top frame, the IP points
  255. ;; to the continuation -- but we haven't
  256. ;; returned and defined its values yet. The
  257. ;; set of live variables is the set that was
  258. ;; live going into the call, minus the set
  259. ;; killed by the call, but not including
  260. ;; values defined by the call.
  261. (begin
  262. (bitvector-copy! tmp (vector-ref inv (1- n)))
  263. (bit-set*! tmp (vector-ref killv (1- n)) #f)
  264. tmp))))
  265. (let lp ((n 0))
  266. (let ((n (bit-position #t live n)))
  267. (if n
  268. (match (vector-ref defs n)
  269. (#(name def-offset slot representation)
  270. (cons (make-binding frame n name slot representation)
  271. (lp (1+ n)))))
  272. '()))))
  273. (lp (1+ n) (- offset (vector-ref parsed n)))))))
  274. (define* (frame-bindings frame #:optional top-frame?)
  275. (let ((ip (frame-instruction-pointer frame)))
  276. (cond
  277. ((find-program-arity ip)
  278. => (lambda (arity)
  279. (available-bindings frame arity ip top-frame?)))
  280. (else '()))))
  281. (define (frame-lookup-binding frame var)
  282. (let lp ((bindings (frame-bindings frame)))
  283. (cond ((null? bindings)
  284. #f)
  285. ((eq? (binding-name (car bindings)) var)
  286. (car bindings))
  287. (else
  288. (lp (cdr bindings))))))
  289. (define (binding-ref binding)
  290. (frame-local-ref (or (binding-frame binding)
  291. (error "binding has no frame" binding))
  292. (binding-slot binding)
  293. (binding-representation binding)))
  294. (define (binding-set! binding val)
  295. (frame-local-set! (or (binding-frame binding)
  296. (error "binding has no frame" binding))
  297. (binding-slot binding)
  298. val
  299. (binding-representation binding)))
  300. (define* (frame-procedure-name frame #:key
  301. (info (find-program-debug-info
  302. (frame-instruction-pointer frame))))
  303. (cond
  304. (info => program-debug-info-name)
  305. ;; We can only try to get the name from the closure if we know that
  306. ;; slot 0 corresponds to the frame's procedure. This isn't possible
  307. ;; to know in general. If the frame has already begun executing and
  308. ;; the closure binding is dead, it could have been replaced with any
  309. ;; other random value, or an unboxed value. Even if we're catching
  310. ;; the frame at its application, before it has started running, if
  311. ;; the callee is well-known and has only one free variable, closure
  312. ;; optimization could have chosen to represent its closure as that
  313. ;; free variable, and that free variable might be some other program,
  314. ;; or even an unboxed value. It would be an error to try to get the
  315. ;; procedure name of some procedure that doesn't correspond to the
  316. ;; one being applied. (Free variables are currently always boxed but
  317. ;; that could change in the future.)
  318. ((primitive-code? (frame-instruction-pointer frame))
  319. (procedure-name (frame-local-ref frame 0 'scm)))
  320. (else #f)))
  321. ;; This function is always called to get some sort of representation of the
  322. ;; frame to present to the user, so let's do the logical thing and dispatch to
  323. ;; frame-call-representation.
  324. (define (frame-arguments frame)
  325. (cdr (frame-call-representation frame)))
  326. ;; Usually the IP is sufficient to identify the procedure being called.
  327. ;; However all primitive applications of the same arity share the same
  328. ;; code. Perhaps we should change that in the future, but for now we
  329. ;; export this function to avoid having to export frame-local-ref.
  330. ;;
  331. (define (frame-instruction-pointer-or-primitive-procedure-name frame)
  332. (let ((ip (frame-instruction-pointer frame)))
  333. (if (primitive-code? ip)
  334. (procedure-name (frame-local-ref frame 0 'scm))
  335. ip)))
  336. ;;;
  337. ;;; Pretty printing
  338. ;;;
  339. ;; Basically there are two cases to deal with here:
  340. ;;
  341. ;; 1. We've already parsed the arguments, and bound them to local
  342. ;; variables. In a standard (lambda (a b c) ...) call, this doesn't
  343. ;; involve any argument shuffling; but with rest, optional, or
  344. ;; keyword arguments, the arguments as given to the procedure may
  345. ;; not correspond to what's on the stack. We reconstruct the
  346. ;; arguments using e.g. for the case above: `(,a ,b ,c). This works
  347. ;; for rest arguments too: (a b . c) => `(,a ,b . ,c)
  348. ;;
  349. ;; 2. We have failed to parse the arguments. Perhaps it's the wrong
  350. ;; number of arguments, or perhaps we're doing a typed dispatch and
  351. ;; the types don't match. In that case the arguments are all on the
  352. ;; stack, and nothing else is on the stack.
  353. (define* (frame-call-representation frame #:key top-frame?)
  354. (let* ((ip (frame-instruction-pointer frame))
  355. (info (find-program-debug-info ip))
  356. (nlocals (frame-num-locals frame)))
  357. (define (find-slot i bindings)
  358. (match bindings
  359. (() #f)
  360. (((and binding ($ <binding> frame idx name slot)) . bindings)
  361. (if (< idx i)
  362. (find-slot i bindings)
  363. (and (= idx i) binding)))))
  364. (define (local-ref i bindings)
  365. (cond
  366. ((not bindings)
  367. ;; This case is only hit for primitives and application
  368. ;; arguments.
  369. (frame-local-ref frame i 'scm))
  370. ((find-slot i bindings)
  371. => (lambda (binding)
  372. (let ((val (frame-local-ref frame (binding-slot binding)
  373. (binding-representation binding))))
  374. ;; It could be that there's a value that isn't clobbered
  375. ;; by a call but that isn't live after a call either. In
  376. ;; that case, if GC runs during the call, the value will
  377. ;; be collected, and on the stack it will be replaced
  378. ;; with the unspecified value. Assume that clobbering
  379. ;; values is more likely than passing the unspecified
  380. ;; value as an argument, and replace unspecified with _,
  381. ;; as if the binding were not available.
  382. (if (unspecified? val) '_ val))))
  383. (else
  384. '_)))
  385. (define (application-arguments)
  386. ;; Case 1.
  387. (map (lambda (local) (local-ref local #f))
  388. ;; Cdr past the 0th local, which is the procedure.
  389. (cdr (iota nlocals))))
  390. (define (reconstruct-arguments bindings nreq nopt kw has-rest? local)
  391. ;; Case 2.
  392. (cond
  393. ((positive? nreq)
  394. (cons (local-ref local bindings)
  395. (reconstruct-arguments bindings
  396. (1- nreq) nopt kw has-rest? (1+ local))))
  397. ((positive? nopt)
  398. (cons (local-ref local bindings)
  399. (reconstruct-arguments bindings
  400. nreq (1- nopt) kw has-rest? (1+ local))))
  401. ((pair? kw)
  402. (cons* (caar kw) (local-ref (cdar kw) bindings)
  403. (reconstruct-arguments bindings
  404. nreq nopt (cdr kw) has-rest? (1+ local))))
  405. (has-rest?
  406. (local-ref local bindings))
  407. (else
  408. '())))
  409. (cons
  410. (or (frame-procedure-name frame #:info info) '_)
  411. (cond
  412. ((find-program-arity ip)
  413. => (lambda (arity)
  414. (if (and top-frame? (eqv? ip (arity-low-pc arity)))
  415. (application-arguments)
  416. (reconstruct-arguments
  417. (available-bindings frame arity ip top-frame?)
  418. (arity-nreq arity)
  419. (arity-nopt arity)
  420. (arity-keyword-args arity)
  421. (arity-has-rest? arity)
  422. 1))))
  423. ((and (primitive-code? ip)
  424. (program-arguments-alist (frame-local-ref frame 0 'scm) ip))
  425. => (lambda (args)
  426. (match args
  427. ((('required . req)
  428. ('optional . opt)
  429. ('keyword . kw)
  430. ('allow-other-keys? . _)
  431. ('rest . rest))
  432. (reconstruct-arguments #f
  433. (length req) (length opt) kw rest 1)))))
  434. (else
  435. (application-arguments))))))
  436. ;;; Misc
  437. ;;;
  438. (define (frame-environment frame)
  439. (map (lambda (binding)
  440. (cons (binding-name binding) (binding-ref binding)))
  441. (frame-bindings frame)))
  442. (define (frame-object-binding frame obj)
  443. (do ((bs (frame-bindings frame) (cdr bs)))
  444. ((or (null? bs) (eq? obj (binding-ref (car bs))))
  445. (and (pair? bs) (car bs)))))
  446. (define (frame-object-name frame obj)
  447. (cond ((frame-object-binding frame obj) => binding-name)
  448. (else #f)))