stack-check.scm 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; This determines the maximum stack depth needed by a code vector.
  3. (define (maximum-stack-use code-vector)
  4. (cond ((not (= (code-vector-ref code-vector 0)
  5. (enum op protocol)))
  6. 0)
  7. ((= (code-vector-ref code-vector 1)
  8. nary-dispatch-protocol) ; has unjumped-to targets
  9. (stack-max code-vector
  10. 6
  11. 0
  12. 0
  13. (do ((i 2 (+ i 1))
  14. (r '() (let ((target (code-vector-ref code-vector i)))
  15. (if (= 0 target)
  16. r
  17. (cons (cons target 0) r)))))
  18. ((= i 6)
  19. r))))
  20. (else
  21. (stack-max code-vector
  22. (protocol-skip code-vector)
  23. 0
  24. 0
  25. '()))))
  26. (define (protocol-skip code-vector)
  27. (let ((protocol (code-vector-ref code-vector 1)))
  28. (cond ((or (= protocol two-byte-nargs-protocol)
  29. (= protocol two-byte-nargs+list-protocol))
  30. 4)
  31. ((= protocol args+nargs-protocol)
  32. 3)
  33. (else
  34. 2))))
  35. ;----------------
  36. ; A vector of procedures, one for each opcode.
  37. (define stack-delta (make-vector op-count #f))
  38. (define-syntax define-delta
  39. (syntax-rules ()
  40. ((define-delta opcode fun)
  41. (vector-set! stack-delta (enum op opcode) fun))))
  42. ; Handle the opcode at I. DEPTH is the current stack depth, MAXIMUM is the
  43. ; maximum so far, and JUMPS is a list of (<index> . <depth>) giving the stack
  44. ; depth at jump targets.
  45. (define (stack-max code-vector i depth maximum jumps)
  46. ((vector-ref stack-delta (code-vector-ref code-vector i))
  47. code-vector
  48. (+ i 1)
  49. depth
  50. maximum
  51. jumps))
  52. ; Do nothing and advance BYTE-SIZE bytes.
  53. (define (nothing byte-size)
  54. (lambda (code-vector i depth maximum jumps)
  55. (stack-max code-vector
  56. (+ i byte-size)
  57. depth
  58. maximum
  59. jumps)))
  60. ; Pop COUNT values from the stack and advance BYTE-SIZE bytes.
  61. (define (popper count byte-args)
  62. (lambda (code-vector i depth maximum jumps)
  63. (stack-max code-vector
  64. (+ i byte-args)
  65. (- depth count)
  66. maximum
  67. jumps)))
  68. ; Push COUNT values onto the stack and advance BYTE-SIZE bytes.
  69. (define (pusher count byte-args)
  70. (lambda (code-vector i depth maximum jumps)
  71. (stack-max code-vector
  72. (+ i byte-args)
  73. (+ depth count)
  74. (imax maximum (+ depth count))
  75. jumps)))
  76. ; Continue on at opcode I. This is used for opcodes that do not fall through
  77. ; to the next instruction. I is either the end of the code vector or the target
  78. ; of a jump or continuation.
  79. (define (continue code-vector i maximum jumps)
  80. (cond ((= i (code-vector-length code-vector))
  81. maximum)
  82. ((assq i jumps)
  83. => (lambda (pair)
  84. (stack-max code-vector i (cdr pair) maximum jumps)))
  85. ((= (code-vector-ref code-vector i)
  86. (enum op cont-data))
  87. (continue code-vector
  88. (+ i 4) ; how do I know this?
  89. maximum
  90. jumps))
  91. (else
  92. (error "stack-max: no one jumps to target" i))))
  93. ; Skip BYTE-ARGS and then continue.
  94. (define (continuer byte-args)
  95. (lambda (code-vector i depth maximum jumps)
  96. (continue code-vector (+ i byte-args) maximum jumps)))
  97. ;----------------
  98. ; Two-byte offsets, here because it is used at top-level.
  99. (define (get-offset code pc)
  100. (+ (* (code-vector-ref code pc)
  101. byte-limit)
  102. (code-vector-ref code (+ pc 1))))
  103. ;----------------
  104. ; All the special opcodes
  105. (define-delta make-env (pusher environment-stack-size 2))
  106. ;(define-delta push (pusher 1 0))
  107. (define-delta pop (popper 1 0))
  108. (define-delta call (continuer 1))
  109. (define-delta big-call (continuer 2))
  110. (define-delta apply (continuer 2))
  111. (define-delta closed-apply (continuer 0))
  112. (define-delta with-continuation (nothing 0)) ; what the compiler requires
  113. (define-delta return (continuer 0))
  114. (define-delta values (continuer 2))
  115. (define-delta closed-values (continuer 0))
  116. (define-delta goto-template (continuer 2))
  117. (define-delta call-template (continuer 3))
  118. ; We should only reach PROTOCOL opcodes in continuations.
  119. (define-delta protocol
  120. (lambda (cv pc depth maximum jumps)
  121. (let ((protocol (code-vector-ref cv pc)))
  122. (if (= protocol call-with-values-protocol)
  123. (continue cv (+ pc 1) maximum jumps)
  124. (call-with-values
  125. (lambda ()
  126. (cond ((or (<= protocol 1)
  127. (= protocol ignore-values-protocol))
  128. (values 1 0))
  129. ((<= protocol maximum-stack-args)
  130. (values 1 protocol))
  131. ((= protocol two-byte-nargs+list-protocol)
  132. (values (+ (get-offset cv (+ pc 1))
  133. 1) ; the rest list
  134. 3))
  135. ((= protocol two-byte-nargs-protocol)
  136. (values (get-offset cv (+ pc 1))
  137. 3))
  138. (else
  139. (error "unknown protocol" protocol))))
  140. (lambda (bytes on-stack)
  141. (stack-max cv
  142. (+ pc bytes)
  143. (+ depth on-stack)
  144. (imax maximum (+ depth on-stack))
  145. jumps)))))))
  146. ; Peephole optimizations
  147. (define-delta push
  148. (lambda (cv pc depth maximum jumps)
  149. (if (= (enum op local0)
  150. (code-vector-ref cv pc))
  151. (begin
  152. (code-vector-set! cv (- pc 1) (enum op push-local0))
  153. (stack-max cv
  154. (+ pc 2)
  155. (+ depth 1)
  156. (imax maximum (+ depth 1))
  157. jumps))
  158. (stack-max cv
  159. pc
  160. (+ depth 1)
  161. (imax maximum (+ depth 1))
  162. jumps))))
  163. (define-delta local0
  164. (lambda (cv pc depth maximum jumps)
  165. (if (= (enum op push)
  166. (code-vector-ref cv (+ pc 1)))
  167. (begin
  168. (code-vector-set! cv (- pc 1) (enum op local0-push))
  169. (stack-max cv
  170. (+ pc 2)
  171. (+ depth 1)
  172. (imax maximum (+ depth 1))
  173. jumps))
  174. (stack-max cv
  175. (+ pc 1)
  176. depth
  177. maximum
  178. jumps))))
  179. ; Pop the given numbers of stack values.
  180. (define-delta make-stored-object
  181. (lambda (cv pc depth maximum jumps)
  182. (let ((args (code-vector-ref cv pc)))
  183. (stack-max cv (+ pc 2) (- depth (- args 1)) maximum jumps))))
  184. ; Skip over the environment specification.
  185. (define (flat-env-checker size fetch)
  186. (lambda (cv pc depth maximum jumps)
  187. (let ((include-*val*? (= 1 (code-vector-ref cv pc)))
  188. (count (fetch cv (+ pc 1))))
  189. (let loop ((i (+ pc 1 size))
  190. (count (if include-*val*?
  191. (- count 1)
  192. count)))
  193. (if (= count 0)
  194. (stack-max cv i depth maximum jumps)
  195. (let ((level-count (fetch cv (+ i 1))))
  196. (loop (+ i 1 size (* level-count size))
  197. (- count level-count))))))))
  198. (define-delta make-flat-env (flat-env-checker 1 code-vector-ref))
  199. (define-delta make-big-flat-env (flat-env-checker 2 get-offset))
  200. ; Temporarily puts COUNT values on the stack.
  201. (define-delta letrec-closures
  202. (lambda (cv pc depth maximum jumps)
  203. (let ((count (get-offset cv pc)))
  204. (stack-max cv
  205. (+ pc (* 2 (+ count 1)))
  206. depth
  207. (max maximum (+ depth count environment-stack-size))
  208. jumps))))
  209. ; Adds the target to the list of jumps.
  210. ; The -1 is to back up over the opcode.
  211. ; Could check that the we agree with the compiler on the size of the stack.
  212. (define-delta make-cont
  213. (lambda (code-vector i depth maximum jumps)
  214. (let ((target (+ i -1 (get-offset code-vector i))))
  215. (stack-max code-vector
  216. (+ i 2) ; eat offset
  217. (+ depth continuation-stack-size)
  218. (max maximum (+ depth continuation-stack-size))
  219. (cons (cons target depth) jumps)))))
  220. ; Add the jump target(s) and either fall-through or not.
  221. ; The -1 is to back up over the opcode.
  222. (define-delta jump-if-false
  223. (lambda (code-vector i depth maximum jumps)
  224. (let ((target (+ i -1 (get-offset code-vector i))))
  225. (stack-max code-vector
  226. (+ i 2) ; eat label
  227. depth
  228. maximum
  229. (cons (cons target depth) jumps)))))
  230. (define-delta jump
  231. (lambda (code-vector i depth maximum jumps)
  232. (let ((target (+ i -1 (get-offset code-vector i))))
  233. (continue code-vector
  234. (+ i 2) ; eat label
  235. maximum
  236. (cons (cons target depth) jumps)))))
  237. (define-delta computed-goto
  238. (lambda (code-vector i depth maximum jumps)
  239. (let ((count (code-vector-ref code-vector i))
  240. (base (- i 1)) ; back up over opcode
  241. (i (+ i 1)))
  242. (let loop ((c 0) (jumps jumps))
  243. (if (= c count)
  244. (stack-max code-vector
  245. (+ i (* 2 count))
  246. depth
  247. maximum
  248. jumps)
  249. (loop (+ c 1)
  250. (cons (cons (+ base (get-offset code-vector (+ i (* c 2))))
  251. depth)
  252. jumps)))))))
  253. ;----------------
  254. ; Fill in the `normal' opcodes using the information in OPCODE-ARG-SPECS.
  255. (define (stack-function arg-specs)
  256. (let loop ((specs arg-specs) (skip 0))
  257. (cond ((null? specs)
  258. (nothing skip))
  259. ((integer? (car specs))
  260. (if (> (car specs) 1)
  261. (popper (- (car specs) 1) skip)
  262. (nothing skip)))
  263. (else
  264. (loop (cdr specs) (+ skip (arg-spec-size (car specs))))))))
  265. (define (arg-spec-size spec)
  266. (case spec
  267. ((nargs byte stob junk) 1)
  268. ((two-bytes offset small-index index) 2)
  269. (else
  270. (error "unknown arg-spec" spec))))
  271. (do ((i 0 (+ i 1)))
  272. ((= i (vector-length stack-delta)))
  273. (if (not (vector-ref stack-delta i))
  274. (vector-set! stack-delta i (stack-function (vector-ref opcode-arg-specs i)))))
  275. ;----------------
  276. ; Utilities
  277. ; Much faster then Scheme's generic function.
  278. (define (imax x y)
  279. (if (< x y) y x))