interp.scm 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  3. ;Need to fix the byte-code compiler to make jump etc. offsets from the
  4. ;beginning of the instruction. (Later: why?)
  5. ; Interpreter state
  6. (define *code-pointer*) ; pointer to next instruction byte
  7. (define *val*) ; last value produced
  8. (define *exception-handlers*) ; vector of procedures, one per opcode
  9. (define *interrupt-handlers*) ; vector of procedures, one per interrupt type
  10. ; These are set when calls or returns occur. We use them to figure out what
  11. ; the current program counter is.
  12. (define *last-code-called*)
  13. (define *last-code-pointer-resumed*)
  14. ; Two registers used only by the RTS (except for one hack; see GET-CURRENT-PORT
  15. ; in prim-io.scm).
  16. (define *current-thread*) ; dynamic state
  17. (define *session-data*) ; session state
  18. ; Finalizers
  19. (define *finalizer-alist*) ; list of (<thing> . <procedure>) pairs
  20. (define *finalize-these*) ; list of such pairs that should be executed
  21. (define *gc-in-trouble?* #f) ; says whether the GC is running out of space
  22. ; Interrupts
  23. (define *enabled-interrupts*) ; bitmask of enabled interrupts
  24. (define s48-*pending-interrupt?*) ; true if an interrupt is pending
  25. (define *interrupted-template*) ; template in place when the most recent
  26. ; interrupt occured - for profiling
  27. (define *interrupted-byte-opcode-return-code*) ; used to return from interrupts
  28. (define *interrupted-native-call-return-code*) ; used to return from interrupts
  29. (define *native-poll-return-code*) ; used to return from interrupts
  30. (define *exception-return-code*) ; used to mark exception continuations
  31. (define *native-exception-return-code*) ; used to mark native exception continuations
  32. (define *call-with-values-return-code*) ; for call-with-values opcode
  33. ; These are referred to from other modules.
  34. (define (val) *val*)
  35. (define (set-val! val) (set! *val* val))
  36. (define (code-pointer) *code-pointer*)
  37. (define (current-thread) *current-thread*)
  38. ; The current proposal is stored in the current thread.
  39. (define (current-proposal)
  40. (record-ref (current-thread) 3))
  41. (define (set-current-proposal! proposal)
  42. (record-set! (current-thread) 3 proposal))
  43. ;----------------
  44. (define (clear-registers)
  45. (reset-stack-pointer false)
  46. (set-code-pointer! *interrupted-byte-opcode-return-code* 0)
  47. (set-code-pointer! *interrupted-native-call-return-code* 0)
  48. (set-code-pointer! *native-poll-return-code* 0)
  49. (set! *last-code-pointer-resumed* *code-pointer*)
  50. (set! *val* unspecific-value)
  51. (set! *current-thread* null)
  52. (shared-set! *session-data* null)
  53. (shared-set! *exception-handlers* null)
  54. (shared-set! *interrupt-handlers* null)
  55. (set! *enabled-interrupts* 0)
  56. (shared-set! *finalizer-alist* null)
  57. (set! *finalize-these* null)
  58. (pending-interrupts-clear!)
  59. (set! s48-*pending-interrupt?* #f)
  60. (set! *os-signal-ring-start* 0)
  61. (set! *os-signal-ring-ready* 0)
  62. (set! *os-signal-ring-end* 0)
  63. (set! *interrupted-template* false)
  64. unspecific-value)
  65. (define (s48-initialize-shared-registers! s-d e-h i-h f-a)
  66. (set! *session-data* s-d)
  67. (set! *exception-handlers* e-h)
  68. (set! *interrupt-handlers* i-h)
  69. (set! *finalizer-alist* f-a))
  70. (define *saved-pc*) ; for saving the pc across GC's
  71. (add-gc-root!
  72. (lambda ()
  73. ; headers may be busted here...
  74. (receive (code pc)
  75. (current-code+pc)
  76. (set! *saved-pc* pc)
  77. (set! *last-code-called* (s48-trace-value code)))
  78. (set! *val* (s48-trace-value *val*))
  79. (set! *current-thread* (s48-trace-value *current-thread*))
  80. (set! *interrupted-byte-opcode-return-code*
  81. (s48-trace-value *interrupted-byte-opcode-return-code*))
  82. (set! *interrupted-native-call-return-code*
  83. (s48-trace-value *interrupted-native-call-return-code*))
  84. (set! *native-poll-return-code*
  85. (s48-trace-value *native-poll-return-code*))
  86. (set! *exception-return-code* (s48-trace-value *exception-return-code*))
  87. (set! *native-exception-return-code* (s48-trace-value *native-exception-return-code*))
  88. (set! *call-with-values-return-code*
  89. (s48-trace-value *call-with-values-return-code*))
  90. (set! *interrupted-template* (s48-trace-value *interrupted-template*))
  91. (shared-set! *session-data*
  92. (s48-trace-value (shared-ref *session-data*)))
  93. (shared-set! *exception-handlers*
  94. (s48-trace-value (shared-ref *exception-handlers*)))
  95. (shared-set! *interrupt-handlers*
  96. (s48-trace-value (shared-ref *interrupt-handlers*)))
  97. (shared-set! *finalize-these*
  98. (s48-trace-value (shared-ref *finalize-these*)))
  99. (trace-finalizer-alist!)
  100. ; These could be moved to the appropriate modules.
  101. (trace-io s48-trace-value)))
  102. (add-post-gc-cleanup!
  103. (lambda (major? in-trouble?)
  104. (set-code-pointer! *last-code-called* *saved-pc*)
  105. (set! *last-code-pointer-resumed* *code-pointer*)
  106. (partition-finalizer-alist!)
  107. (close-untraced-channels! s48-extant? s48-trace-value)
  108. (set! *gc-in-trouble?* in-trouble?)
  109. (note-interrupt! (if major?
  110. (enum interrupt post-major-gc)
  111. (enum interrupt post-minor-gc)))))
  112. ;----------------
  113. ; Dealing with the list of finalizers.
  114. ;
  115. ; Pre-gc:
  116. ; Trace the contents of every finalizer object, updating them in oldspace.
  117. ; If any contains a pointer to itself, quit and trace it normally.
  118. ; If any have already been copied, ignore it.
  119. ; Post-gc:
  120. ; Check each to see if each has been copied. If not, copy it. There is
  121. ; no need to trace any additional pointers.
  122. ; Walk down the finalizer alist, tracing the procedures and the contents of
  123. ; the things.
  124. (define (trace-finalizer-alist!)
  125. (let loop ((alist (shared-ref *finalizer-alist*)))
  126. (if (not (vm-eq? alist null))
  127. (let* ((pair (vm-car alist)))
  128. (if (not (s48-extant? (vm-car pair))) ; if not already traced
  129. (s48-trace-stob-contents! (vm-car pair)))
  130. (vm-set-cdr! pair (s48-trace-value (vm-cdr pair)))
  131. (loop (vm-cdr alist))))))
  132. ; Walk down the finalizer alist, separating out the pairs whose things
  133. ; have been copied.
  134. (define (partition-finalizer-alist!)
  135. (let loop ((alist (shared-ref *finalizer-alist*)) (okay null) (goners null))
  136. (if (vm-eq? alist null)
  137. (begin
  138. (shared-set! *finalizer-alist* okay)
  139. (set! *finalize-these* (vm-append! goners *finalize-these*)))
  140. (let* ((alist (s48-trace-value alist))
  141. (pair (s48-trace-value (vm-car alist)))
  142. (thing (vm-car pair))
  143. (next (vm-cdr alist))
  144. (traced? (s48-extant? thing)))
  145. (vm-set-car! pair (s48-trace-value thing))
  146. (vm-set-car! alist pair)
  147. (cond (traced?
  148. (vm-set-cdr! alist okay)
  149. (loop next alist goners))
  150. (else
  151. (vm-set-cdr! alist goners)
  152. (loop next okay alist)))))))
  153. (define (vm-append! l1 l2)
  154. (if (vm-eq? l1 null)
  155. l2
  156. (let ((last-pair (let loop ((l l1))
  157. (if (vm-eq? (vm-cdr l) null)
  158. l
  159. (loop (vm-cdr l))))))
  160. (vm-set-cdr! last-pair l2)
  161. l1)))
  162. ;----------------
  163. (define (set-code-pointer! code pc)
  164. ; (if (= code 100384375)
  165. ; (breakpoint "set-code-pointer!"))
  166. (set! *last-code-called* code)
  167. (set! *code-pointer* (code+pc->code-pointer code pc)))
  168. (define (code+pc->code-pointer code pc)
  169. (address+ (address-after-header code) pc))
  170. (define (code-pointer->pc code pointer)
  171. (address-difference pointer
  172. (address-after-header code)))
  173. (define (within-code? code-pointer code)
  174. (let ((start (address-after-header code)))
  175. (and (address<= start code-pointer)
  176. (address< code-pointer
  177. (address+ start
  178. (safe-byte-vector-length code))))))
  179. ; This has to operate with broken hearts.
  180. (define (safe-byte-vector-length code)
  181. (code-vector-length (let ((header (stob-header code)))
  182. (if (stob? header)
  183. header
  184. code))))
  185. (define (current-code-vector)
  186. (if (within-code? *code-pointer* *last-code-called*)
  187. *last-code-called*
  188. (let ((code (code-pointer->code *last-code-pointer-resumed*)))
  189. (if (within-code? *code-pointer* code)
  190. code
  191. (error "VM error: unable to locate current code vector"
  192. (address->integer *code-pointer*)
  193. *last-code-called*
  194. (address->integer *last-code-pointer-resumed*))))))
  195. (define (code-pointer->code code-pointer)
  196. (let ((pc (fetch-two-bytes (address- code-pointer 5))))
  197. (address->stob-descriptor (address- code-pointer pc))))
  198. ; Silly utility that should be elsewhere.
  199. (define (fetch-two-bytes pointer)
  200. (+ (shift-left (fetch-byte pointer) 8)
  201. (fetch-byte (address+ pointer 1))))
  202. (define (current-code+pc)
  203. (let ((code (current-code-vector)))
  204. (values code
  205. (code-pointer->pc code *code-pointer*))))
  206. ; These two templates are used when pushing continuations for calls to
  207. ; interrupt and exception handlers. The continuation data gives zero
  208. ; as the size, which tells the stack-tracing code that the real size
  209. ; is in the continuation just below the saved registers.
  210. (define (initialize-interpreter+gc) ;Used only at startup
  211. (let ((key (ensure-space (* 6 return-code-size))))
  212. (set! *interrupted-byte-opcode-return-code*
  213. (make-return-code ignore-values-protocol
  214. #xffff ; dummy template offset
  215. (enum op resume-interrupted-opcode-to-byte-code)
  216. #xFFFF ; escape value
  217. key))
  218. (set! *interrupted-native-call-return-code*
  219. (make-return-code ignore-values-protocol
  220. #xffff ; dummy template offset
  221. (enum op resume-interrupted-call-to-native-code)
  222. #xFFFF ; escape value
  223. key))
  224. (set! *native-poll-return-code*
  225. (make-return-code ignore-values-protocol
  226. #xffff ; dummy template offset
  227. (enum op resume-native-poll)
  228. #xFFFF ; escape value
  229. key))
  230. (set! *exception-return-code*
  231. (make-return-code 1 ; want exactly one return value
  232. #xffff ; dummy template offset
  233. (enum op return-from-exception)
  234. #xFFFF ; escape value
  235. key))
  236. (set! *native-exception-return-code*
  237. (make-return-code 1 ; want exactly one return value
  238. #xffff ; dummy template offset
  239. (enum op return-from-native-exception)
  240. #xFFFF ; escape value
  241. key))
  242. (set! *call-with-values-return-code*
  243. (make-return-code call-with-values-protocol
  244. #xffff ; dummy template offset
  245. 0 ; opcode is not used
  246. 1
  247. key))))
  248. ; Users of the above templates have to skip over the continuation data.
  249. (define continuation-data-size 3)
  250. ;----------------
  251. ; Continuations
  252. (define (pop-continuation!)
  253. (set! *code-pointer* (pop-continuation-from-stack))
  254. (set! *last-code-pointer-resumed* *code-pointer*))
  255. ;----------------
  256. ; Instruction stream access
  257. (define (code-byte index)
  258. (fetch-byte (address+ *code-pointer* (+ index 1))))
  259. (define (code-offset index)
  260. (adjoin-bits (code-byte index)
  261. (code-byte (+ index 1))
  262. bits-used-per-byte))
  263. (define (get-literal code-index)
  264. (template-ref (stack-ref (code-offset code-index))
  265. (code-offset (+ code-index 2))))
  266. ; Return the current op-code. CODE-ARGS is the number of argument bytes that
  267. ; have been used.
  268. (define (current-opcode)
  269. (code-byte -1))
  270. ; INTERPRET is the main instruction dispatch for the interpreter.
  271. ;(define trace-instructions? #f)
  272. ;(define *bad-count* 0)
  273. ;(define *i* 0)
  274. (define (interpret code-pointer)
  275. ; (if (and trace-instructions? (> *i* *bad-count*))
  276. ; (receive (code pc)
  277. ; (current-code+pc)
  278. ; (write-instruction code pc 1 #f)
  279. ; (check-stack)))
  280. ; (set! *i* (+ *i* 1))
  281. ((vector-ref opcode-dispatch (fetch-byte code-pointer))))
  282. (define (continue bytes-used)
  283. (set! *code-pointer* (address+ *code-pointer* (+ bytes-used 1)))
  284. (goto interpret *code-pointer*))
  285. (define (continue-with-value value bytes-used)
  286. (set! *val* value)
  287. (goto continue bytes-used))
  288. ;----------------
  289. ; Exception syntax
  290. ; For restartable exceptions the saved code-pointer points to the instruction
  291. ; following the offending one. For all other exceptions it points to the
  292. ; offending instruction.
  293. ;
  294. ; The ...* versions evaluate the exception enum argument, the plain ones
  295. ; invoke the enumeration.
  296. (define-syntax raise-exception
  297. (syntax-rules ()
  298. ((raise-exception why byte-args stuff ...)
  299. (raise-exception* (enum exception why) byte-args stuff ...))))
  300. (define-syntax count-exception-args
  301. (syntax-rules ()
  302. ((count-exception-args) 0)
  303. ((count-exception-args arg1 rest ...)
  304. (+ 1 (count-exception-args rest ...)))))
  305. (define-syntax raise-exception*
  306. (syntax-rules ()
  307. ((raise-exception* why byte-args arg1 ...)
  308. (begin
  309. (push-exception-setup! why (+ byte-args 1)) ; add 1 for the opcode
  310. (push arg1) ...
  311. (goto raise (count-exception-args arg1 ...))))))
  312. ;----------------
  313. ; Opcodes
  314. (define (uuo)
  315. (raise-exception unimplemented-instruction
  316. 0
  317. (enter-fixnum (fetch-byte *code-pointer*))))
  318. (define opcode-dispatch (make-vector op-count uuo))
  319. (define-syntax define-opcode
  320. (syntax-rules ()
  321. ((define-opcode op-name body ...)
  322. (vector-set! opcode-dispatch (enum op op-name) (lambda () body ...)))))
  323. ;----------------
  324. ; Exceptions
  325. ; The system reserves enough stack space to allow for an exception at any time.
  326. ; If the reserved space is used a gc must be done before the exception handler
  327. ; is called.
  328. ; New exception handlers in *val*.
  329. (define-opcode set-exception-handlers!
  330. (cond ((or (not (vm-vector? *val*))
  331. (< (vm-vector-length *val*) op-count))
  332. (raise-exception wrong-type-argument 0 *val*))
  333. (else
  334. (let ((temp (shared-ref *exception-handlers*)))
  335. (shared-set! *exception-handlers* *val*)
  336. (goto continue-with-value
  337. temp
  338. 0)))))
  339. ; The current opcode and the exception are pushed as arguments to the handler.
  340. ; INSTRUCTION-SIZE is the size of the current instruction and is used to jump
  341. ; to the next instruction when returning. The exception is saved in the
  342. ; continuation for use in debugging.
  343. (define *native-exception-cont* 0)
  344. (define (reset-native-exception-cont!)
  345. (set! *native-exception-cont* 0))
  346. ;;; Eventually, the native code wants the VM to detect and handle and
  347. ;;; excpetion In this case, the native code sets
  348. ;;; *native-exception-cont* to the continuation of the exception. If
  349. ;;; this is detected here, push-native-exception-setup! fills the
  350. ;;; exception data diffently and installs return-from-native-exception
  351. ;;; as opcode
  352. (define (push-exception-setup! exception instruction-size)
  353. ; (breakpoint "exception continuation")
  354. (if (= 0 *native-exception-cont*)
  355. (receive (code pc)
  356. (current-code+pc)
  357. (push-exception-continuation! (code+pc->code-pointer *exception-return-code*
  358. return-code-pc)
  359. (enter-fixnum pc)
  360. code
  361. (enter-fixnum exception)
  362. (enter-fixnum instruction-size)))
  363. (begin
  364. (push *native-exception-cont*)
  365. (set-cont-to-stack!)
  366. (write-string "handling exception for nc " (current-error-port))
  367. (write-integer *native-exception-cont* (current-error-port))
  368. (push-native-exception-continuation! (code+pc->code-pointer *native-exception-return-code*
  369. return-code-pc)
  370. (enter-fixnum (current-opcode))
  371. *native-exception-cont*
  372. (enter-fixnum exception))
  373. (reset-native-exception-cont!)))
  374. (push (enter-fixnum (current-opcode)))
  375. (push (enter-fixnum exception)))
  376. (define-opcode return-from-exception
  377. (receive (pc code exception size)
  378. (pop-exception-data)
  379. (let* ((pc (extract-fixnum pc))
  380. (opcode (code-vector-ref code pc)))
  381. (cond ((okay-to-proceed? opcode)
  382. (set-code-pointer! code (+ pc (extract-fixnum size)))
  383. (goto interpret *code-pointer*))
  384. (else
  385. (set-code-pointer! code pc)
  386. (raise-exception illegal-exception-return 0 exception))))))
  387. (define-opcode return-from-native-exception
  388. (receive (opcode code exception ignore)
  389. (pop-exception-data)
  390. (let ((opcode (extract-fixnum opcode)))
  391. (cond ((okay-to-proceed? opcode)
  392. (write-string "returning to nc " (current-error-port))
  393. (write-integer (fetch *stack*) (current-error-port))
  394. (return-values 0 null 0))
  395. (else
  396. (set-code-pointer! code 0) ; Uahh...
  397. (raise-exception illegal-exception-return 0 exception))))))
  398. ; It's okay to proceed if the opcode is a data operation, which are all those
  399. ; from EQ? on up, or references to globals (where the use can supply a value).
  400. (define (okay-to-proceed? opcode)
  401. (or (<= (enum op eq?) opcode)
  402. (= opcode (enum op global))))
  403. (define no-exceptions? #f)
  404. (define (raise nargs)
  405. ; (let ((opcode (enumerand->name (extract-fixnum (stack-ref (+ nargs 1))) op))
  406. ; (why (enumerand->name (extract-fixnum (stack-ref nargs)) exception)))
  407. ; (if (and no-exceptions?
  408. ; (not (and (eq? 'write-char opcode)
  409. ; (eq? 'buffer-full/empty why))))
  410. ; (breakpoint "exception check ~A ~A ~A" opcode why nargs)))
  411. ;; try to be helpful when all collapses
  412. (let* ((opcode (extract-fixnum (stack-ref (+ nargs 1))))
  413. (lose (lambda (message)
  414. (write-string "Template UIDs: " (current-error-port))
  415. (report-continuation-uids (current-code-vector)
  416. (current-error-port))
  417. (newline (current-error-port))
  418. (let ((why (extract-fixnum (stack-ref nargs))))
  419. (if (and (eq? why (enum exception undefined-global))
  420. (fixnum? (location-id (stack-ref (- nargs 1)))))
  421. (error message opcode why
  422. (extract-fixnum
  423. (location-id (stack-ref (- nargs 1)))))
  424. (error message opcode why)))))
  425. (handlers (shared-ref *exception-handlers*)))
  426. (if (not (vm-vector? handlers))
  427. (lose "exception-handlers is not a vector"))
  428. (set! *val* (vm-vector-ref handlers opcode))
  429. (if (not (closure? *val*))
  430. (lose "exception handler is not a closure"))
  431. ;; We add 2, one for the opcode, one for the exception itself
  432. (goto call-exception-handler (+ nargs 2) opcode)))
  433. ;----------------
  434. ; Literals and local variables.
  435. ; Loaded from the stack, template, or environment into *val*, with the
  436. ; template or environment obtained from the stack.
  437. (define-opcode stack-indirect
  438. (goto continue-with-value
  439. (d-vector-ref (stack-ref (code-byte 0))
  440. (code-byte 1))
  441. 2))
  442. ; same as stack-indirect, but serves as annotation for native-code
  443. ; compiler
  444. (define-opcode template-ref
  445. (goto continue-with-value
  446. (d-vector-ref (stack-ref (code-byte 0))
  447. (code-byte 1))
  448. 2))
  449. (define-opcode big-template-ref
  450. (goto continue-with-value
  451. (d-vector-ref (stack-ref (code-offset 0))
  452. (code-offset 2))
  453. 4))
  454. (define-opcode push+stack-indirect
  455. (push *val*)
  456. (goto continue-with-value
  457. (d-vector-ref (stack-ref (code-byte 0))
  458. (code-byte 1))
  459. 2))
  460. (define-opcode stack-indirect+push
  461. (push (d-vector-ref (stack-ref (code-byte 0))
  462. (code-byte 1)))
  463. (goto continue 2))
  464. (define-opcode big-stack-indirect
  465. (goto continue-with-value
  466. (d-vector-ref (stack-ref (code-offset 0))
  467. (code-offset 2))
  468. 4))
  469. (define-opcode unassigned-check
  470. (if (vm-eq? *val* unassigned-marker)
  471. (raise-exception unassigned-local 0)
  472. (goto continue 0)))
  473. (define-opcode integer-literal
  474. (goto continue-with-value
  475. (integer-literal 0)
  476. 1))
  477. (define-opcode push+integer-literal
  478. (push *val*)
  479. (goto continue-with-value
  480. (integer-literal 0)
  481. 1))
  482. (define-opcode integer-literal+push
  483. (push (integer-literal 0))
  484. (goto continue 1))
  485. ; PreScheme does not have a SIGNED-BYTE-REF so we bias the value by 128.
  486. (define (integer-literal offset)
  487. (enter-fixnum (- (code-byte offset)
  488. 128)))
  489. ;----------------
  490. ; Global variable access
  491. (define-opcode global ;Load a global variable.
  492. (let* ((template (stack-ref (code-offset 0)))
  493. (index (code-offset 2))
  494. (location (template-ref template index)))
  495. (set! *val* (contents location))
  496. (if (undefined? *val*) ;unbound or unassigned
  497. (raise-exception undefined-global 4
  498. location template (enter-fixnum index))
  499. (goto continue 4))))
  500. (define-opcode set-global!
  501. (let* ((template (stack-ref (code-offset 0)))
  502. (index (code-offset 2))
  503. (location (template-ref template index)))
  504. (cond ((vm-eq? (contents location) unbound-marker)
  505. (raise-exception undefined-global 4
  506. location template (enter-fixnum index) *val*))
  507. (else
  508. (set-contents! location *val*)
  509. (goto continue-with-value
  510. unspecific-value
  511. 4)))))
  512. ;----------------
  513. ; Stack operation
  514. (define-opcode push ;Push *val* onto the stack.
  515. (push *val*)
  516. (goto continue 0))
  517. (define-opcode push-false
  518. (push false)
  519. (goto continue 0))
  520. (define-opcode pop ;Pop *val* from the stack.
  521. (goto continue-with-value
  522. (pop)
  523. 0))
  524. (define-opcode pop-n
  525. (add-cells-to-stack! (- (code-offset 0)))
  526. (goto continue 2))
  527. (define-opcode push-n
  528. (do ((n (code-offset 0) (- n 1)))
  529. ((= 0 n))
  530. (push false))
  531. (goto continue 2))
  532. (define-opcode stack-ref
  533. (goto continue-with-value
  534. (stack-ref (code-byte 0))
  535. 1))
  536. (define-opcode big-stack-ref
  537. (goto continue-with-value
  538. (stack-ref (code-offset 0))
  539. 2))
  540. (define-opcode push+stack-ref
  541. (push *val*)
  542. (goto continue-with-value
  543. (stack-ref (code-byte 0))
  544. 1))
  545. (define-opcode stack-ref+push
  546. (push (stack-ref (code-byte 0)))
  547. (goto continue 1))
  548. (define-opcode stack-set!
  549. (stack-set! (code-byte 0) *val*)
  550. (goto continue 1))
  551. (define-opcode big-stack-set!
  552. (stack-set! (code-offset 0) *val*)
  553. (goto continue 2))
  554. (define-opcode stack-shuffle!
  555. (push *val*)
  556. (let ((n-moves (code-byte 0)))
  557. (do ((move 0 (+ 1 move)))
  558. ((= move n-moves))
  559. (let ((index (+ 1 (* 2 move))))
  560. (stack-set! (code-byte (+ 1 index))
  561. (stack-ref (code-byte index)))))
  562. (goto continue-with-value
  563. (pop)
  564. (+ 1 (* 2 n-moves)))))
  565. (define-opcode big-stack-shuffle!
  566. (push *val*)
  567. (let ((n-moves (code-offset 0)))
  568. (do ((move 0 (+ 1 move)))
  569. ((= move n-moves))
  570. (let ((index (+ 2 (* 4 move))))
  571. (stack-set! (code-offset (+ 2 index))
  572. (stack-ref (code-offset index)))))
  573. (goto continue-with-value
  574. (pop)
  575. (+ 2 (* 4 n-moves)))))
  576. ;----------------
  577. ; LAMBDA
  578. ; No longer used.
  579. ;(define-opcode closure
  580. ; (receive (env key)
  581. ; (if (= 0 (code-byte 2))
  582. ; (let ((key (ensure-space (+ closure-size (current-env-size)))))
  583. ; (values (preserve-current-env key) key))
  584. ; (let ((key (ensure-space closure-size)))
  585. ; (values *val* key)))
  586. ; (goto continue-with-value
  587. ; (make-closure (get-literal 0) env key)
  588. ; 3)))
  589. ; (enum op make-[big-]flat-env)
  590. ; number of values
  591. ; number of closures
  592. ; [offset of template in frame
  593. ; offsets of templates in template]
  594. ; number of variables in frame (size)
  595. ; offsets of vars in frame
  596. ; [offset of env in frame
  597. ; number of vars in env
  598. ; offsets of vars in level]*
  599. ;
  600. ; All numbers and offsets are one byte for make-flat-env and two bytes for
  601. ; make-big-flat-env.
  602. (define (flat-env-maker size fetch)
  603. (define (make-env)
  604. (let* ((total-count (fetch 0))
  605. (closures (fetch size))
  606. (key (ensure-space (+ (vm-vector-size total-count)
  607. (* closures closure-size))))
  608. (new-env (vm-make-vector total-count key)))
  609. ; (format #t "[flat env with ~D values]~%" total-count)
  610. (goto continue-with-value
  611. new-env
  612. (if (= closures 0)
  613. (fill-env new-env 0 (+ size size) total-count)
  614. (make-closures new-env closures key total-count)))))
  615. (define (make-closures new-env count key total-count)
  616. ; (format #t "[making ~D closures]~%" count)
  617. (let* ((offset (+ size size))
  618. (template (stack-ref (fetch offset))))
  619. (do ((count count (- count 1))
  620. (i 0 (+ i 1))
  621. (offset (+ offset size) (+ offset size)))
  622. ((= count 0)
  623. (fill-env new-env i offset total-count))
  624. (vm-vector-set! new-env
  625. i
  626. (make-closure (template-ref template (fetch offset))
  627. new-env
  628. key)))))
  629. (define (fill-env new-env i offset total-count)
  630. (do ((count (fetch offset) (- count 1))
  631. (i i (+ i 1))
  632. (offset (+ offset size) (+ offset size)))
  633. ((= count 0)
  634. (if (< i total-count)
  635. (finish-env new-env i offset total-count)
  636. offset))
  637. (vm-vector-set! new-env i (stack-ref (fetch offset)))))
  638. (define (finish-env new-env i offset total-count)
  639. (let loop ((i i)
  640. (offset offset))
  641. (if (= i total-count)
  642. offset
  643. (let ((env (stack-ref (fetch offset)))
  644. (count (fetch (+ offset size))))
  645. ; (format #t "[getting ~D more values from ~D]~%"
  646. ; count
  647. ; (fetch offset))
  648. (do ((count count (- count 1))
  649. (i i (+ i 1))
  650. (offset (+ offset size size) (+ offset size)))
  651. ((= count 0)
  652. (loop i offset))
  653. (vm-vector-set! new-env
  654. i
  655. (vm-vector-ref env (fetch offset))))))))
  656. make-env)
  657. (let ((one-byte-maker (flat-env-maker 1 code-byte)))
  658. (define-opcode make-flat-env (one-byte-maker)))
  659. (let ((two-byte-maker (flat-env-maker 2 code-offset)))
  660. (define-opcode make-big-flat-env (two-byte-maker)))
  661. ;----------------
  662. ; Preserve the current continuation and put it in *val*.
  663. (define-opcode current-cont
  664. (let ((key (ensure-space (current-continuation-size))))
  665. (goto continue-with-value
  666. (copy-current-continuation-to-heap key)
  667. 0)))
  668. (define-opcode with-continuation
  669. (set-current-continuation! (pop))
  670. (goto perform-application 0))
  671. ;----------------
  672. ; Control flow
  673. ; IF
  674. (define-opcode jump-if-false
  675. (cond ((false? *val*)
  676. (set! *code-pointer*
  677. (address+ *code-pointer*
  678. (code-offset 0)))
  679. (goto interpret *code-pointer*))
  680. (else
  681. (goto continue 2))))
  682. ; Unconditional jumps
  683. (define-opcode jump
  684. (set! *code-pointer*
  685. (address+ *code-pointer*
  686. (code-offset 0)))
  687. (goto interpret *code-pointer*))
  688. ; Same thing except the other way.
  689. (define-opcode jump-back
  690. (set! *code-pointer*
  691. (address- *code-pointer*
  692. (code-offset 0)))
  693. (goto interpret *code-pointer*))
  694. ; Computed goto
  695. ; Goto index is in *val*, the next byte is the number of offsets specified
  696. ; The default is to jump to the instruction following the offsets
  697. ; The instruction stream looks like
  698. ; op/computed-goto max offset0 offset1 ... offsetmax-1 code-for-default...
  699. (define-opcode computed-goto
  700. (if (not (fixnum? *val*))
  701. (raise-exception wrong-type-argument -1 *val*) ; back up over opcode
  702. (let ((max (code-byte 0))
  703. (val (extract-fixnum *val*)))
  704. (let ((offset (if (and (>= val 0)
  705. (< val max))
  706. (code-offset (+ (* val 2) 1))
  707. (+ (* max 2) 2))))
  708. (set! *code-pointer* (address+ *code-pointer* offset))
  709. (goto interpret *code-pointer*)))))
  710. ;----------------
  711. ; Miscellaneous primitive procedures
  712. (define-opcode unassigned
  713. (goto continue-with-value
  714. unassigned-marker
  715. 0))
  716. (define-opcode unspecific
  717. (goto continue-with-value
  718. unspecific-value
  719. 0))