diff options
Diffstat (limited to 'execution.e')
| -rw-r--r-- | execution.e | 100 |
1 files changed, 2 insertions, 98 deletions
diff --git a/execution.e b/execution.e index 1b9e84d..c3f99f2 100644 --- a/execution.e +++ b/execution.e @@ -145,104 +145,8 @@ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -~ Macro next -~ ~~~~~~~~~~ -~ -~ Include this inline at the end of a word implemented in machine-code. -~ Conceptually, it returns. What it actually does is do the next thing the -~ caller would do, which is call the next word from the caller's array of -~ word pointers. -~ -~ This is a widespread technique in Forth implementation, referred to as -~ indirect threaded code. It's "threaded" in the sense that each word takes -~ responsibility for finishing up by following the notional thread through the -~ metaphorical labyrinth to figure out the next word that its caller wants to -~ run after it. In other words, control never directly returns to the parent, -~ it proceeds directly to the sibling. -~ -~ Registers in: -~ -~ * rsi points to the address of the word to execute -~ -~ Registers out: -~ -~ * rax points to the codeword in the contents of the word that was executed -~ * rsi points to the next word-address after this one -~ -~ Flags -~ * DF = 0 is required -~ -~ (base address -- new base address) -: pack-next - ~ Copy the next word's address from *rsi into rax. Increment rsi (as per the - ~ DF flag). - lods64 - - ~ Load the codeword from the word's contents, and jump to the interpreter it - ~ points to. - :rax jmp-abs-indirect-reg64 ; - - -~ Macro beforenext -~ ~~~~~~~~~~~~~~~~ -~ -~ Sometimes we want to transfer control from a word implemented in -~ machine-code to another word, without coming back after, as if we were -~ simply jumping to it. This is an innovation of ours; Jonesforth doesn't do -~ it. It is similar to the tail-call optimization that many Lisp dialects -~ have. -~ -~ This implementation will work regardless of how the receiving word is -~ implemented. It impersonates the "next" snippet, setting up rax to point -~ to the codeword then jumping to the interpreter. Since it doesn't change -~ the control stack or rsi, when the receiving word eventually invokes -~ "next"; it will pick up in the same place as if this sending word had done -~ it. -~ -~ Thus, notionally we are doing just this one transfer of control before -~ eventually getting around to inlining "next". Hence the name. -~ -~ (target address, base address -- new base address) -: pack-beforenext - ~ Do a permanent transfer of control by setting rax and invoking the - ~ codeword. Of course, we could jump to docol ourselves but this will work - ~ regardless of what the receiving codeword is. - :rax mov-reg64-imm64 - :rax jmp-abs-indirect-reg64 ; - - -~ Macros pushcontrol -~ popcontrol -~ ~~~~~~~~~~~~~~~~~~ -~ -~ Include these inline to push an address onto the control stack, or pop -~ one off of it. You will recall the control stack is kept in rbp. The -~ parameter is given in a user-specified register. -~ -~ Jonesforth's analogous macros are called PUSHRSP and POPRSP but I think -~ that's super confusing, since rsp is also the name of a register, but a -~ different one. I guess it was less confusing in 32-bit, since esp doesn't -~ start with an "r". Anyway, this has to be named something that -~ distinguishes it from Intel's PUSH and POP opcodes, so... -~ -~ "Load effective address" is just a cute way to do arithmetic on a -~ register, here. To push or pop we decrement or increment rbp by 8. To -~ actually interact with the space in the stack, we indirect through rbp. -~ -~ Registers in and out: -~ -~ * rbp points to the top of the control stack. -~ -~ (source register, base address -- new base address) -: pack-pushcontrol - swap :rbp -8 :rbp lea-reg64-disp8-reg64 - swap :rbp 0 mov-disp8-reg64-reg64 ; - -~ (target register, base address -- new base address) -: pack-popcontrol - :rbp 0 3roll mov-reg64-disp8-reg64 - :rbp 8 :rbp lea-reg64-disp8-reg64 ; +~ The macros next, beforenext, pushcontrol, and popcontrol are implemented +~ in execution-support.e. It's a good idea to go read about them now. ~ Constants ~ ~~~~~~~~~ |