I have kept pondering the rtl code-base and it's pretty cool work wingo has put up. I can't say that I fully grasp his intentions for the code base but I do have added some useful infrastructure in order to be able smooth the
experience of this exploration.
One of the main drawback of the current wip-rtl version is that there is no support for toplevel forms yet.
Here is how I added this feature,
it's possible to add 'macros' to the rtl-assembler via define-macro-assembler, so here is the toplevel one,
(define-macro-assembler (toplevel asm dst sym) (let ((s (emit-non-immediate asm sym)) (d (emit-non-immediate asm (current-module))) (v (intern-constant asm 0 #:slot #t))) (emit-toplevel-ref asm dst v d s)))
emit-non-immediate will return a label to an allocated constant object sym and (current-module) (I needed to add to the codebase the possibility of constant modules)
intern-constant is similar in nature, but using the #:slot key will force it to allocate a SCM slot and
return a label to a slot initialized to #f (for a place to put the ref to a toplevel box used to cache the lookup of the toplevel) . This feature was also added by me, it's a bit unclean because this slot is not a constant and we might want to
separate regions of writable memory and non writable memory. Anyway this works for now.
Another hack was to add a header to the begin-program code. I (define-macro-assembler (begin-program asm label . f-meta)
(emit-label asm label) (let ((meta (make-meta label #f (asm-start asm) #f))) (set-asm-meta! asm (cons meta (asm-meta asm))) (emit asm 0) (emit asm 0) (emit asm 0) ;;Mark that we have a meta prefix
(reset-asm-start! asm) (let* ((i (asm-start asm)) (a (asm-cur asm))) (meta-fend-set! meta (lambda (n) (u32-set! a i n)))) (emit asm 0) (reset-asm-start! asm) (emit-load-constant asm 0 f-meta)))
I allowed an argument f-meta e.g. function meta data like function signature data structure. that could be added in some way reachable from the header of the code, I do not know yet if there already are present some meta information, wingo's disassemble routine would indicate
that the meta structure above was stored and locals, in a header but I'm not clear if that was implemented.
I also needed to get the actual code into a bytevector in order to use wingo's dissasemble routine
that was already in rtl.scm. To do this I needed the size of the program.
Also I wan't to execute native code, and this code need to be hooked into the header, so I ended up doing.
u32 HEADER: 0 | If nonzero there is native code that can be executed
0 | ------- 0 | If this u32 is zero then there is metadata, if nonzero then program starts here -------- u32 | Size of the program --------- u32 | Instruction that represent a fetch of the meta constant
u32 | --------- Program starts here
+ some extra hackity hack and I can now do,
As usual c compiles a lambda of the argument code which is evaluated and then f will be the lambda inside (c ...) (define f ((c (lambda (x) (pk 1))))
And a little more information for when printing them notice the (x) scheme@(guile-user)> f $1 = #<rtl-program 158f240 1373314 (x)>
Finally toplevel ref work by executing the function
scheme@(guile-user)> (f 1)
;;; (1) $3 = 1
Fun fun indeed. There are many tangents to take here, one would be to add more metadata like source information, the assembler can be improved where one lookup constants and presents them nicer
function names as meta information, variable names and more meta information in the assembler would also be good to have in order to get better disassemble printouts.