stack.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  3. ; The stack grows from higher addresses to lower ones.
  4. ; *STACK-BEGIN* and *STACK-END* delimit the stack portion of memory.
  5. ; *STACK* points to the value at the top of the stack.
  6. ; *STACK-LIMIT* is value against which stack requests are checked. There is a
  7. ; buffer area between the limit and the actual end of the stack. The buffer
  8. ; is large enough to contain the default procedure stack requirement plus the
  9. ; space needed to make a call to an exception plus an interrupts plus some
  10. ; slack for safety's sake.
  11. ;
  12. ; Continuations on the stack look like:
  13. ;
  14. ; gc mask
  15. ; size of continuation (two bytes)
  16. ; *cont* --> code-pointer ------------> return protocol
  17. ; operand stack opcodes ...
  18. ; ...
  19. ; frame values (including template and lexical environment)
  20. ; ...
  21. ;
  22. ; Continuations on the heap look like:
  23. ;
  24. ; header
  25. ; tagged pointer --> pc as a fixnum
  26. ; code vector
  27. ; next continuation
  28. ; operand stack
  29. ; ...
  30. ; frame values
  31. ; ...
  32. ;
  33. ; The code that copies continuations back and forth converts between the
  34. ; two representations. Most continuations never get copied off of the
  35. ; stack so we usually save a bit of time by not putting headers on them.
  36. ; This number of slots at the top of the stack are filled with a funny value
  37. ; so that we can detect overruns.
  38. (define stack-warning-limit 30)
  39. ; The supposedly unused space at the end of the stack is marked with this
  40. ; value so that we can detect incursions.
  41. (define stack-marker #xf0f0f0f)
  42. ; We need at least this amount of space for the stack.
  43. (define stack-slack
  44. (+ default-stack-space
  45. continuation-stack-size ; *bottom-of-stack*
  46. (+ continuation-stack-size 13) ; exceptions need at most 14 values
  47. ; (long pole is external exceptions with
  48. ; exception + procedure-name + 10 irritants +
  49. ; saved-exception + stack-block)
  50. (+ continuation-stack-size 7) ; interrupts need at most 7 values
  51. ; (also from examining the code)
  52. (+ stack-warning-limit 2))) ; safety
  53. ; *BOTTOM-OF-STACK* is a stack continuation that lies a the base of the stack.
  54. (define *stack-begin*)
  55. (define *stack-end*)
  56. (define *stack*)
  57. (define s48-*stack-limit*)
  58. (define *real-stack-limit*)
  59. ; Current continuation. This points not to the top frame on the stack,
  60. ; which has no code pointer (because its code pointer is being used by
  61. ; the interpreter), but to the top complete frame on the stack. This
  62. ; is updated for non-tail calls and returns.
  63. (define *cont*)
  64. ; At the bottom of the stack is a special continuation that is never removed.
  65. ; When it is invoked it copies the next continuation out of the heap (if there
  66. ; is any such) and invokes that instead.
  67. (define *bottom-of-stack*)
  68. (define *heap-continuation*)
  69. ; Initialize the stack and related registers. All sizes are in descriptors.
  70. (define (initialize-stack+gc start have-size)
  71. (let ((required-size (+ available-stack-space stack-slack)))
  72. (receive (start size)
  73. (if (>= have-size required-size)
  74. (values start have-size)
  75. (let ((stack (allocate-memory (cells->a-units required-size))))
  76. (if (null-address? stack)
  77. (error "out of memory, unable to continue"))
  78. (values stack required-size)))
  79. (set! *stack-begin* start)
  80. (set! *stack-end* (address+ start (cells->a-units size)))
  81. (set! *real-stack-limit*
  82. (address+ *stack-begin* (cells->a-units stack-slack)))
  83. (set! s48-*stack-limit* *real-stack-limit*)
  84. (set! *stack* *stack-end*)
  85. (set! *cont* (integer->address false))
  86. (do ((a start (address1+ a)))
  87. ((address= a *stack-end*))
  88. (store! a stack-marker))
  89. (let* ((key (ensure-space return-code-size))
  90. (code (make-return-code bottom-of-stack-protocol
  91. #xffff ; dummy template offset
  92. 0 ; opcode (never executed)
  93. 0 ; size
  94. key)))
  95. (push false)
  96. (make-continuation-on-stack (address+ (address-after-header code)
  97. return-code-pc)
  98. 0)) ; offset
  99. (set! *bottom-of-stack* *cont*)
  100. (set! *heap-continuation* false))))
  101. (define (reset-stack-pointer base-continuation)
  102. (set! *stack* *bottom-of-stack*)
  103. (set! *heap-continuation* base-continuation)
  104. (set! *cont* *bottom-of-stack*))
  105. ;----------------
  106. ; Utilities
  107. (define (within-stack? p)
  108. (and (stob? p)
  109. (>= p (address->integer *stack-begin*))
  110. (<= p (address->integer *stack-end*))))
  111. (define (stack-size)
  112. (address-difference *stack-end* *stack-begin*))
  113. ; We need an additional 3 descriptors per continuation (code-pointer expands
  114. ; to header, code, pc, cont). A continuation may be as small as one descriptor.
  115. ; Our choices are: multiply by four, count the continuations, or check the heap
  116. ; as we go. For now I'll just multiply.
  117. (define (current-stack-size)
  118. (* 4 (a-units->cells (address-difference *stack-end* *stack*))))
  119. ; Add CELLS cells onto the stack.
  120. ; The stack grows towards negative memory.
  121. (define (add-cells-to-stack! cells)
  122. (set! *stack* (address- *stack* (cells->a-units cells))))
  123. (define (the-pointer-before x)
  124. (address- x (cells->a-units 1)))
  125. (define (push x) ; check for overflow is done when continuations are pushed
  126. (add-cells-to-stack! 1)
  127. (store! *stack* x))
  128. (define (pop)
  129. (let ((v (fetch *stack*)))
  130. (add-cells-to-stack! -1)
  131. v))
  132. ; Use the stack as a vector, with (STACK-REF 0) => current top of stack
  133. (define (stack-ref index)
  134. (fetch (address+ *stack* (cells->a-units index))))
  135. (define (stack-set! index value)
  136. (store! (address+ *stack* (cells->a-units index)) value))
  137. (define (pointer-to-stack-arguments)
  138. *stack*)
  139. (define (remove-stack-arguments count)
  140. (add-cells-to-stack! (- count)))
  141. ; Look at the return protocol to see if a continuation is byte code or
  142. ; native code.
  143. (define (stack-continuation-is-byte-code? cont)
  144. (byte-code-return-pointer? (integer->address (stack-cont-code-pointer cont))))
  145. (define (byte-code-return-pointer? pointer)
  146. (= 0 (bitwise-and (fetch-byte (address+ pointer 1)) ; skip protocol marker
  147. native-protocol-mask)))
  148. ;----------------------------------------------------------------
  149. ; Dealing with stack continuations.
  150. ; A heuristic - stack continuations must point into the stack and be four-byte
  151. ; aligned.
  152. (define (stack-continuation? x)
  153. (and (address>= x *stack-begin*)
  154. (address<= x *stack-end*)
  155. (= 0 (bitwise-and (address->integer x)
  156. #b11))))
  157. (define (stack-cont-code-pointer cont)
  158. (assert (stack-continuation? cont))
  159. (integer->address (fetch cont)))
  160. (define (set-stack-cont-code-pointer! cont code-pointer)
  161. (assert (stack-continuation? cont))
  162. (store! cont (address->integer code-pointer)))
  163. ; The +1 is because the size does not include return pointer.
  164. (define (stack-cont-continuation cont)
  165. (address+ cont
  166. (cells->a-units (+ (stack-continuation-size cont)
  167. 1))))
  168. ;----------------------------------------------------------------
  169. ; Pending interrupts are signalled by setting the stack limit to -1.
  170. ; This allows us to use a single test to check for stack space and
  171. ; pending interrupts.
  172. (define (interrupt-flag-set?)
  173. (address= s48-*stack-limit* (integer->address -1)))
  174. (define (clear-interrupt-flag!)
  175. (set! s48-*stack-limit* *real-stack-limit*))
  176. (define (set-interrupt-flag!)
  177. (set! s48-*stack-limit* (integer->address -1)))
  178. (define (stack-space-check space-test)
  179. (lambda (need)
  180. (if (space-test need s48-*stack-limit*)
  181. #f
  182. (let ((interrupt? (interrupt-flag-set?)))
  183. (clear-interrupt-flag!)
  184. (if (not (space-test need *real-stack-limit*))
  185. (begin
  186. (s48-copy-stack-into-heap)
  187. (if (not (space-test need *real-stack-limit*))
  188. (error "VM's stack is too small (how can this happen?)"))))
  189. interrupt?))))
  190. ; S48-*STACK-LIMIT* is offset by DEFAULT-STACK-SPACE to make this test faster.
  191. (define ensure-default-procedure-space!
  192. (let ((check (stack-space-check (lambda (ignore limit)
  193. (address<= limit *stack*)))))
  194. (lambda ()
  195. (check 0))))
  196. ; Check 1: if SPACE is DEFAULT-STACK-SPACE this is the same as above.
  197. ; Check 2: as SPACE grows this gets harder to satisfy.
  198. (define (available-on-stack? space limit)
  199. (address<= limit
  200. (address- *stack*
  201. (cells->a-units (- space
  202. default-stack-space)))))
  203. (define ensure-stack-space! (stack-space-check available-on-stack?))
  204. ;----------------------------------------------------------------
  205. ; Getting and setting the current continuation.
  206. ; Called when replacing the current continuation with a new one.
  207. (define (set-current-continuation! cont)
  208. (if (continuation? cont)
  209. (copy-continuation-from-heap! cont 0)
  210. (reset-stack-pointer cont)))
  211. ; For returns (see call.scm).
  212. (define (current-continuation-code-pointer)
  213. ; (format #t "~%[cont code pointer ~S (from ~S)]"
  214. ; (integer->address (fetch *cont*))
  215. ; *cont*)
  216. (integer->address (fetch *cont*)))
  217. ;----------------------------------------------------------------
  218. ; Various random operations used by CALL-WITH-VALUES.
  219. ;
  220. ; Remove the current continuation from the chain.
  221. (define (skip-current-continuation! nargs)
  222. (set! *cont* (stack-cont-continuation *cont*))
  223. (move-args-above-cont! nargs))
  224. (define (current-continuation-ref index)
  225. (fetch (address+ *cont* (cells->a-units (+ index 1)))))
  226. (define (shrink-and-reset-continuation! code-pointer)
  227. (set! *cont* (address1+ *cont*))
  228. (set-stack-cont-code-pointer! *cont* code-pointer))
  229. (define (remove-current-frame)
  230. (set! *stack* *cont*))
  231. ;----------------------------------------------------------------
  232. (define (make-continuation-on-stack code-pointer offset)
  233. ; (set! *old-cont* *cont*)
  234. (set! *cont* (address+ *stack* (cells->a-units offset)))
  235. ; (format #t "~%[new cont at ~S with code pointer ~S(~S)]"
  236. ; *cont*
  237. ; code-pointer
  238. ; (fetch-two-bytes (address- code-pointer 2)))
  239. (store! *cont* (address->integer code-pointer)))
  240. ; (if (and (address<= *stack-begin* *old-cont*)
  241. ; (address<= *old-cont* *stack-end*)
  242. ; (not (address= *old-cont*
  243. ; (stack-cont-continuation *cont*))))
  244. ; (breakpoint "make-continuation-on-stack"))
  245. (define (push-continuation! code-pointer)
  246. (push (address->integer code-pointer))
  247. (set! *cont* *stack*))
  248. ; Interrupt and exception continuations come in all sizes. We push the size
  249. ; on the stack just below the return pointer. The pointer itself has a key
  250. ; size that tells to look on the stack.
  251. (define (push-adlib-continuation! code-pointer)
  252. (push (enter-fixnum (+ (operands-on-stack) 1))) ; count includes itself
  253. (push-continuation! code-pointer)
  254. (assert (= (raw-stack-continuation-size *cont*)
  255. #xFFFF)))
  256. ; Set the stack to point to the current continuation, make the next one down
  257. ; be the new current contnuation, and return the code pointer.
  258. (define (pop-continuation-from-stack)
  259. (set! *stack* *cont*)
  260. ; (format #t "~%[popping cont at ~S with code pointer ~S(~S)]"
  261. ; *stack*
  262. ; (integer->address (fetch *stack*))
  263. ; (stack-continuation-size *cont*))
  264. (set! *cont* (stack-cont-continuation *cont*))
  265. (integer->address (pop)))
  266. (define (set-cont-to-stack!)
  267. (set! *cont* *stack*))
  268. ; Pushing exception data. We do this in a chunk to ensure that we agree
  269. ; with the VM as to which value is where.
  270. (define (push-exception-continuation! code-pointer pc code exception inst-size)
  271. (add-cells-to-stack! exception-continuation-cells)
  272. (let ((data (address->stob-descriptor *stack*))
  273. (size (enter-fixnum (operands-on-stack))))
  274. (data-init! data exception-cont-size-index size)
  275. (data-init! data exception-cont-pc-index pc)
  276. (data-init! data exception-cont-code-index code)
  277. (data-init! data exception-cont-exception-index exception)
  278. (data-init! data exception-cont-instruction-size-index inst-size)
  279. (push-continuation! code-pointer)))
  280. (define (push-native-exception-continuation! code-pointer pc code exception)
  281. (add-cells-to-stack! exception-continuation-cells)
  282. (let ((data (address->stob-descriptor *stack*))
  283. (size (enter-fixnum (operands-on-stack))))
  284. (data-init! data exception-cont-size-index size)
  285. (data-init! data exception-cont-pc-index pc)
  286. (data-init! data exception-cont-code-index code)
  287. (data-init! data exception-cont-exception-index exception)
  288. (data-init! data exception-cont-instruction-size-index 0) ;empty
  289. (push-continuation! code-pointer)))
  290. (define (pop-exception-data)
  291. (let ((data (address->stob-descriptor *stack*)))
  292. (add-cells-to-stack! (- exception-continuation-cells))
  293. (values (data-ref data exception-cont-pc-index)
  294. (data-ref data exception-cont-code-index)
  295. (data-ref data exception-cont-exception-index)
  296. (data-ref data exception-cont-instruction-size-index))))
  297. ; The indexes into the data are the indexes into the continuation minus
  298. ; the normal continuation cells. We use raw STORE! and FETCH to avoid
  299. ; having to put a temporary header on the data (D-VECTOR-INIT! and
  300. ; D-VECTOR-REF have assertions that check for the presence of a header).
  301. ;
  302. ; We subtract off CONTINUATION-CELLS because the indexes are for heap
  303. ; continuations which have that many extra values pushed on top.
  304. (define (data-init! data index value)
  305. (store! (address+ (address-after-header data)
  306. (cells->a-units (- index continuation-cells)))
  307. value))
  308. (define (data-ref data index)
  309. (fetch (address+ (address-after-header data)
  310. (cells->a-units (- index continuation-cells)))))
  311. ;----------------
  312. ; Error reporting
  313. (define (report-continuation-uids current-code out)
  314. (let* ((template (find-template *stack*
  315. (operands-on-stack)
  316. current-code))
  317. (not-first? (maybe-write-template template #f out)))
  318. (really-show-stack-continuation-uids not-first? out)))
  319. (define (show-stack-continuation-uids)
  320. (really-show-stack-continuation-uids #f (current-error-port)))
  321. (define (really-show-stack-continuation-uids not-first? out)
  322. (let loop ((cont *cont*) (not-first? not-first?))
  323. (if (address= cont *bottom-of-stack*)
  324. (really-show-heap-continuation-uids *heap-continuation* not-first? out)
  325. (loop (stack-cont-continuation cont)
  326. (maybe-write-template (stack-cont-template cont)
  327. not-first?
  328. out))))
  329. 0)
  330. (define (show-heap-continuation-uids cont)
  331. (really-show-heap-continuation-uids cont #f (current-error-port)))
  332. (define (really-show-heap-continuation-uids cont not-first? out)
  333. (let loop ((cont cont) (not-first? not-first?))
  334. (if (continuation? cont)
  335. (loop (continuation-cont cont)
  336. (maybe-write-template (heap-cont-template cont)
  337. not-first?
  338. out)))))
  339. (define (stack-cont-template cont)
  340. (find-template (address1+ cont)
  341. (stack-continuation-size cont)
  342. (code-pointer->code (stack-cont-code-pointer cont))))
  343. (define (heap-cont-template cont)
  344. (find-template (address-after-header cont)
  345. (continuation-length cont)
  346. (continuation-code cont)))
  347. (define (code-pointer->code code-pointer)
  348. (let ((pc (fetch-two-bytes (address- code-pointer 5))))
  349. (address->stob-descriptor (address- code-pointer pc))))
  350. ; Look for a template whose code is CODE-VECTOR among the COUNT descriptors
  351. ; starting from START.
  352. (define (find-template start count code-vector)
  353. (let loop ((i 0))
  354. (if (= i count)
  355. false
  356. (let ((next (fetch (address+ start (cells->a-units i)))))
  357. (if (and (template? next)
  358. (vm-eq? (template-code next)
  359. code-vector))
  360. next
  361. (loop (+ i 1)))))))
  362. ; Native code continuations have code vectors instead of templates.
  363. ; We could look for a template in the continuation and see if it has
  364. ; the same code vector.
  365. (define (maybe-write-template template not-first? out)
  366. (if not-first?
  367. (begin
  368. (write-string " <- " out)
  369. (unspecific))) ; avoid type error
  370. (if (template? template)
  371. (let ((name (template-name template)))
  372. (cond ((fixnum? name)
  373. (write-integer (extract-fixnum name) out))
  374. ((and (record? name)
  375. (vm-string? (record-ref name 2)))
  376. (write-vm-string (record-ref name 2) out))
  377. ((and (record? name)
  378. (vm-symbol? (record-ref name 2)))
  379. (write-vm-string (vm-symbol->string (record-ref name 2))
  380. out))
  381. (else
  382. (write-string "?" out))))
  383. (write-string " ?? " out))
  384. #t)
  385. (define (stack-warning-message)
  386. (do ((a *stack-begin* (address1+ a)))
  387. ((not (= stack-marker (fetch a)))
  388. (let ((unused (a-units->cells (address-difference a *stack-begin*))))
  389. (if (< unused stack-warning-limit)
  390. (begin
  391. (newline (current-error-port))
  392. (write-string "[Alert: stack overconsumption ("
  393. (current-error-port))
  394. (write-integer unused (current-error-port))
  395. (write-string "); please inform the Scheme 48 implementors]"
  396. (current-error-port))
  397. (newline (current-error-port))
  398. (set! *stack-warning?* #f)))))))