Preserve state across hot code reload!!

This commit is contained in:
Jeremy Penner 2021-05-15 11:50:53 -04:00
parent a5dbc5fcfc
commit 1db882c150
8 changed files with 58 additions and 16 deletions

Binary file not shown.

View file

@ -115,7 +115,7 @@
; takes the form [:op args]
; pdat - a parsed dat; takes the form {:type type :addr addr ...}
(local dat-parser {})
(fn new-block [last-symbol] {:type :block :pdats [] :symbols {} :globals {} : last-symbol})
(fn new-block [last-symbol] {:type :block :pdats [] :preserved {} :symbols {} :globals {} : last-symbol})
(fn parse-dats [block dats]
(each [_ dat (ipairs dats)]
@ -139,7 +139,10 @@
(table.insert block.pdats pdat)
(when pdat.globals
(each [name _ (pairs pdat.globals)]
(tset block.globals name (length block.pdats))))))))
(tset block.globals name (length block.pdats))))
(when pdat.preserved
(each [name pdat-preserved (pairs pdat.preserved)]
(tset block.preserved name pdat-preserved)))))))
block)
(fn dat-parser.op [op]
@ -166,6 +169,13 @@
nil)
(fn dat-parser.align [pad] {:type :pad :align (. pad 2)})
(fn dat-parser.hot-preserve [[_ label & dats] block]
(let [preserve-block (new-block)]
(tset block.preserved label preserve-block)
(tset preserve-block.globals label true)
(parse-dats preserve-block [label])
(parse-dats preserve-block dats)
preserve-block))
(local pdat-processor {
:op {}
@ -338,6 +348,17 @@
(self.dbgfile:close)
(set self.dbgfile nil))
self)
:read-hotswap
(fn [self machine]
(let [hotswap {}]
(each [_ block (pairs self.org-to-block)]
(each [label pdat (pairs block.preserved)]
(tset hotswap label (machine:read pdat.addr pdat.size))))
hotswap))
:write-hotswap
(fn [self machine hotswap]
(each [label bytes (pairs hotswap)]
(machine:write (self:lookup-addr label) bytes)))
:upload
(fn [self machine]
(if machine.upload (machine:upload self)

View file

@ -385,8 +385,9 @@
(fn vm.var [self name init]
(self.code:append name [:jsr :$dovar]
[:hot-preserve (.. :G-HOT-PRESERVE- name)
(if (= (type init) :table) init
[:dw init])))
[:dw init])]))
(vm:def :$doconst ; usage: [jsr :$doconst] followed by two bytes
(vm:reserve)

View file

@ -132,7 +132,7 @@
[:jmp (if (= (or map.moveword "") "") :move-noop map.moveword)]
[:jmp (if (= (or map.loadword "") "") :next map.loadword)]))
(vm.code:append :map-ptr [:db 0] :map-page [:db 0])
(vm.code:append :map-ptr [:db 0] [:hot-preserve :map-page [:db 0]])
(vm:word :map :lit :map-ptr :get)
(vm:word :entity-count :map 240 :+ :bget)
(vm:word :map-player-yx-ptr 241 :+)

File diff suppressed because one or more lines are too long

View file

@ -45,7 +45,7 @@
[:vm :hires
:lit :map1 :load-level
(vm:forever
(vm:hotswap-sync :lit :map1 :load-level)
(vm:hotswap-sync :full-redraw)
:interactive-eval-checkpoint
:handle-key
)

View file

@ -87,6 +87,20 @@
(when self.monitor (self.monitor:shutdown-session))
(when (nrepl:connected?) (nrepl:disconnect))
(set self.breakpoints {}))
(fn Machine.read [self addr len]
(-> (self:coro-eval
(.. "(let [bencode (require :bencode)
addr " addr "
len " len "
mem (. manager.machine.devices ::maincpu :spaces :program)]
(var bytes \"\")
(print :reading len :from addr)
(for [i 1 len]
(set bytes (.. bytes (string.char (mem:read_u8 (+ addr i -1))))))
bytes)"))
; result is piped through fennelview; have to eval it to turn it back into bytes
; would be nice if io.write worked
(fennel.eval)))
(fn Machine.write [self addr bytes]
(if (> (bytes:len) 0x1000)
(do (self:write addr (bytes:sub 1 0x1000))
@ -103,11 +117,11 @@
(self:eval "(manager.machine:soft_reset)")
(self:eval (string.format "(emu.keypost \"CALL-151\\n %xG\\n\")" (prg:lookup-addr prg.start-symbol))))
(fn Machine.reboot [self] (self:eval "(manager.machine:hard_reset)"))
(fn Machine.coro-eval [self code]
(fn Machine.coro-eval [self code ?handlers]
(var result nil)
(local append-to-result #(set result (.. (or result "") $2)))
(self:eval code
(self:coro-handlers (coroutine.running) {:value append-to-result :out append-to-result}))
(self:coro-handlers (coroutine.running) {:value append-to-result :out append-to-result} ?handlers))
(coroutine.yield)
(or result "<no result>"))
(fn Machine.dbgcmd [self cmd ?handlers]
@ -130,10 +144,14 @@
(fn Machine.hotswap [self prg-old prg-new]
(local addr (prg-old:lookup-addr :debug-stub))
(self:set-bp addr
(fn [] (self:clear-bp addr)
#(util.in-coro (fn []
(self:clear-bp addr)
(local hotswap (prg-old:read-hotswap self))
(prg-new:upload self)
(prg-new:write-hotswap self hotswap)
(self:jump (prg-new:lookup-addr :on-hotswap))
(self:continue))))
(self:continue)))))
(fn Machine.overlay [self prg-overlay]
(self:step)
(prg-overlay:upload self)

View file

@ -19,7 +19,7 @@
(fn Session.shutdown-session [self]
(set self.queue [])
(set self.in-progress false)
(set self.sesion nil))
(set self.session nil))
(fn Session.cleanup-handlers [self]
{:status/done #(self:done-msg)
@ -63,9 +63,11 @@
(fn Session.eval [self code ?handlers]
(self:send {:op :eval : code} ?handlers))
(fn Session.input-handler [self input]
{:status/need-input #(self:send-oob {:op :stdin :stdin input})})
(fn Session.eval-input [self code input ?handlers]
(self:send {:op :eval : code}
(lume.merge (or ?handlers {})
{:status/need-input #(self:send-oob {:op :stdin :stdin input})})))
(lume.merge (or ?handlers {}) (self:input-handler input))))
Session