;; Copyright 2018-2023 ;; Kaz Kylheku ;; Vancouver, Canada ;; All rights reserved. ;; ;; Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions are met: ;; ;; 1. Redistributions of source code must retain the above copyright notice, ;; this list of conditions and the following disclaimer. ;; ;; 2. Redistributions in binary form must reproduce the above copyright notice, ;; this list of conditions and the following disclaimer in the documentation ;; and/or other materials provided with the distribution. ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ;; POSSIBILITY OF SUCH DAMAGE. (load "vm-param") (defstruct oc-base nil (:static deprecated nil) (:method synerr (me fmt . args) (error `opcode @{me.symbol}: @fmt` . args)) (:method chk-arg-count (me n syntax) (when (neq (length (rest syntax)) n) me.(synerr "~s arguments required; ~s is invalid" n syntax))) (:method chk-arg-count-min (me n syntax) (when (< (length (rest syntax)) n) me.(synerr "~s arguments required; ~s is invalid" n syntax))) (:method backpatch (me asm at offs) (ignore asm at offs) (asm-error `@{me.symbol} doesn't backpatch`))) (compile-only (defstruct assembler nil buf bstr (max-treg 0) (labdef (hash)) (labref (hash)) (:static imm-width (relate '(si mi bi) '(10 16 32))) (:static sign-bits (relate '(fixnum bignum chr) '(1 1 0))) (:static operand-name (relate '(si mi bi l r rs d ds n o) '("small immediate" "medium immediate" "big immediate" "label" "register operand" "register small operand" "register destination operand" "register small destination operand" "integer" "any object"))))) (defmeth assembler :postinit (me) (cond (me.buf (set me.bstr (make-buf-stream me.buf))) (me.bstr (set me.buf (get-buf-from-stream me.bstr))) (t (set me.bstr (make-buf-stream) me.buf (get-buf-from-stream me.bstr))))) (defmeth assembler cur-pos (me) (seek-stream me.bstr 0 :from-current)) (defmeth assembler set-pos (me pos) (seek-stream me.bstr pos :from-start)) (defmeth assembler lookup-label (me sym oc) (condlet (((n [me.labdef sym])) n) (t (push (cons oc (trunc me.(cur-pos) 4)) [me.labref sym]) 0))) (defmeth assembler define-label (me sym) (let* ((pos me.(cur-pos)) (ins (trunc pos 4))) (set [me.labdef sym] ins) (each ((entry (del [me.labref sym]))) (tree-bind (oc . offs) entry me.(set-pos (* 4 offs)) oc.(backpatch me (* 4 offs) ins))) me.(set-pos pos) ins)) (defmeth assembler read-buf (me bytes) (let ((buf (make-buf bytes))) (when (neql (fill-buf buf 0 me.bstr) bytes) (asm-error "read past instruction block")) buf)) (defmeth assembler put-word (me word) (let* ((buf (make-buf 0))) (buf-put-u32 buf 0 word) (put-buf buf 0 me.bstr))) (defmeth assembler put-insn (me code extension operand) (let ((word (logior (ash code 26) (ash extension 16) operand)) (buf (make-buf 0))) (buf-put-u32 buf 0 word) (put-buf buf 0 me.bstr))) (defmeth assembler put-pair (me op1 op2) (let ((word (logior (ash op1 16) op2)) (buf (make-buf 0))) (buf-put-u32 buf 0 word) (put-buf buf 0 me.bstr))) (defmeth assembler get-word (me) (let* ((buf me.(read-buf (sizeof uint32)))) (buf-get-u32 buf 0))) (defmeth assembler get-insn (me) (let* ((buf me.(read-buf (sizeof uint32))) (word (buf-get-u32 buf 0))) (list (ash word -26) (logtrunc (ash word -16) 10) (logtrunc word 16)))) (defmeth assembler get-pair (me) (let* ((buf me.(read-buf (sizeof uint32))) (word (buf-get-u32 buf 0))) (list (ash word -16) (logtrunc word 16)))) (defmeth assembler immediate-fits-type (me arg operand-type) (and (member (typeof arg) '(fixnum chr)) (<= (+ (width arg) [me.sign-bits (typeof arg)] 2) [me.imm-width operand-type]))) (defmeth assembler parse-args (me oc syntax pattern) (mapcar (lambda (type arg n) (let ((parg (caseql type ((si mi bi) (when me.(immediate-fits-type arg type) arg)) (l (cond ((is-label arg) me.(lookup-label arg oc)) ((integerp arg) arg))) (n (if (integerp arg) arg)) (o arg) ((r rs d ds) (cond ((null arg) 0) ((consp arg) (parse-compound-operand arg)) ((symbolp arg) (parse-operand (symbol-name arg))))) (t (asm-error "invalid arg type spec ~s" type))))) (unless (or parg (eq type 'o)) oc.(synerr "argument ~a of ~s invalid; ~a expected" n syntax [me.operand-name type])) (when (and (member type '(d ds)) (or (zerop parg))) oc.(synerr "argument ~a of ~s cannot be destination" n syntax)) (when (and (member type '(rs ds)) (not (small-op-p parg))) oc.(synerr "argument ~a of ~s isn't a small register" n syntax)) (when (and (member type '(r rs d ds)) (< parg %lev-size%)) (set me.max-treg (max parg me.max-treg))) parg)) pattern (rest syntax) (range 1))) (defmeth assembler asm-one (me syntax) (let ((oc (cond ((is-label syntax) [%oc-hash% 'label]) ((consp syntax) [%oc-hash% (car syntax)])))) (unless oc (asm-error "invalid instruction ~s" syntax)) oc.(asm me syntax))) (defmeth assembler asm (me insns) (each ((i insns)) me.(asm-one i)) (unless (empty me.labref) (asm-error "dangling label references")) (whenlet ((n (cdr [find-max me.labdef : cdr]))) (unless (< -1 n (len me.buf)) (asm-error "labels outside of code")))) (defmeth assembler dis-one (me) (tree-bind (code extension operand) me.(get-insn) (let ((oc [%oc-hash% code])) oc.(dis me extension operand)))) (defmeth assembler dis (me) me.(set-pos 0) (build (while (< me.(cur-pos) (len me.buf)) (add me.(dis-one))))) (defmeth assembler dis-listing (me : (stream *stdout*)) (let ((p 0) (c 0) (l (len me.buf))) me.(set-pos p) (while (< p l) (let* ((dis me.(dis-one)) (dis-txt (cat-str [mapcar tostringp dis] " ")) (q me.(cur-pos))) (inc c) me.(set-pos p) (format stream "~,5d: ~,08X ~a\n" (trunc p 4) me.(get-word) dis-txt) (while (< (inc p 4) q) (format stream "~,5d: ~,08X\n" (trunc p 4) me.(get-word))) me.(set-pos q) (set p q))) c)) (defvarl %oc-list-builder% (new list-builder)) (defvarl %oc-hash% (hash)) (defparml %oc-code% 0) (defun asm-error (msg . args) (error `~s: @msg` 'assembler . args)) (defun register-opcode (oc) %oc-list-builder%.(add oc) (set [%oc-hash% oc.symbol] oc) (set [%oc-hash% oc.code] oc)) (defun is-label (obj) (or (keywordp obj) (and (symbolp obj) (not (symbol-package obj))))) (defun parse-compound-operand (cons) (tree-case cons ((sym arg) (when (< -1 arg %lev-size%) (caseq sym ((t) arg) (d (+ arg %lev-size%))))) ((sym arg1 arg2) (when (and (<= 0 arg1 %max-v-lev%) (<= 0 arg2 %max-lev-idx%)) (caseq sym (v (+ (* (ssucc arg1) %lev-size%) arg2))))))) (defun parse-operand (str) (cond ((r^$ #/t[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?/ str) (int-str [str 1..:] 16)) ((r^$ #/d[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?/ str) (+ %lev-size% (int-str [str 1..:] 16))) ((r^$ #/v[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]/ str) (let ((lv (int-str [`0@{str[1..:]}` -5..-3] 16)) (ix (int-str [str -3..:] 16))) (+ (* %lev-size% (ssucc lv)) ix))))) (eval-only (defmacro with-lev-idx ((lev-var idx-var) val-expr . body) (with-gensyms (val-var) ^(let* ((,val-var ,val-expr) (,lev-var (ash ,val-var (- %lev-bits%))) (,idx-var (logtrunc ,val-var %lev-bits%))) ,*body)))) (defun operand-to-sym (val) (with-lev-idx (lv ix) val (caseql lv (0 (if (zerop ix) nil (intern (fmt "t~s" ix)))) (1 (intern (fmt "d~s" ix))) (t (intern (fmt "v~,02X~,03X" (ppred lv) ix)))))) (defun operand-to-exp (val) (with-lev-idx (lv ix) val (caseql lv (0 (if (zerop ix) nil ^(t ,ix))) (1 ^(d ,ix)) (t ^(v ,(ppred lv) ,ix))))) (defun bits-to-obj (bits width) (let ((tag (logtrunc bits 2)) (val (ash bits -2))) (caseq tag (1 (sign-extend val (- width 2))) (2 (chr-int val)) (t (error "~s: bad immediate operand: ~x" 'assembler bits))))) (defun small-op-p (val) (with-lev-idx (lv ix) val (and (<= 0 ix %max-sm-lev-idx%) (<= 0 lv %max-sm-lev%)))) (defun enc-small-op (val) (with-lev-idx (lv ix) val (logior (ash lv %sm-lev-bits%) ix))) (defun small-op-to-sym (sval) (let ((lv (ash sval (- %sm-lev-bits%))) (ix (logtrunc sval %sm-lev-bits%))) (operand-to-sym (+ (* lv %lev-size%) ix)))) (defstruct backpatch-low16 nil (:method backpatch (me asm at offs) (ignore me) (tree-bind (hi t) asm.(get-pair) asm.(set-pos at) asm.(put-pair hi offs)))) (defstruct backpatch-high16 nil (:method backpatch (me asm at offs) (ignore me) (tree-bind (t lo) asm.(get-pair) asm.(set-pos at) asm.(put-pair offs lo)))) (defvarl %backpatch-low16% (new backpatch-low16)) (defvarl %backpatch-high16% (new backpatch-high16)) (eval-only (defmacro defopcode (class symbol code . slot-defs) ^(symacrolet ((auto (pinc %oc-code%))) (defstruct ,class oc-base (:static symbol ',symbol) (:static code ,code) ,*slot-defs) (register-opcode (new ,class)))) (defmacro defopcode-derived (class symbol code orig-class) ^(symacrolet ((auto (pinc %oc-code%))) (defstruct ,class ,orig-class (:static symbol ',symbol) (:static code ,code)) (register-opcode (new ,class)))) (defmacro defopcode-alias (alias-symbol orig-symbol) ^(let ((oc [%oc-hash% ',orig-symbol])) (set [%oc-hash% ',alias-symbol] oc)))) (defopcode op-label label nil (:method asm (me asm syntax) (ignore me) (unless (is-label syntax) asm.(synerr "label must be keyword or gensym")) asm.(define-label syntax)) (:method dis (me asm extension operand) (ignore me asm extension operand))) (defopcode op-noop noop auto (:method asm (me asm syntax) me.(chk-arg-count 0 syntax) asm.(put-insn me.code 0 0)) (:method dis (me asm extension operand) (ignore asm extension operand) ^(,me.symbol))) (defopcode op-frame frame auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (lev size) asm.(parse-args me syntax '(n n)) (unless (<= 2 lev %max-v-lev%) me.(synerr "level must range from 2 to ~a" %max-v-lev%)) (unless (<= 0 size %lev-size%) me.(synerr "size must range from 0 to ~a" %lev-size%)) asm.(put-insn me.code lev size))) (:method dis (me asm lev size) (ignore asm) ^(,me.symbol ,lev ,size))) (defopcode-derived op-sframe sframe auto op-frame) (defopcode-derived op-dframe dframe auto op-frame) (defopcode op-end end auto (:method asm (me asm syntax) me.(chk-arg-count 1 syntax) (let ((res (car asm.(parse-args me syntax '(r))))) asm.(put-insn me.code 0 res))) (:method dis (me asm extension res) (ignore asm extension) ^(,me.symbol ,(operand-to-sym res)))) (defopcode-alias jend end) (defopcode-alias xend end) (defopcode-derived op-prof prof auto op-end) (defopcode op-call call auto (:method asm (me asm syntax) me.(chk-arg-count-min 2 syntax) (let* ((nargs (pred (len syntax))) (syn-pat (repeat '(r) (succ nargs))) (funargs (ppred nargs)) (args asm.(parse-args me syntax syn-pat))) asm.(put-insn me.code funargs (pop args)) (while args (let ((x (pop args)) (y (or (pop args) 0))) asm.(put-pair y x))))) (:method dis (me asm funargs arg0) (build (add me.symbol) (add (operand-to-sym arg0)) (inc funargs 1) (while (> funargs 0) (dec funargs 2) (tree-bind (y x) asm.(get-pair) (add (operand-to-sym x)) (unless (minusp funargs) (add (operand-to-sym y)))))))) (defopcode-derived op-apply apply auto op-call) (defopcode op-gcall gcall auto (:method asm (me asm syntax) me.(chk-arg-count-min 2 syntax) (let* ((nargs (pred (len syntax))) (syn-pat (list* 'r 'n (repeat '(r) (sssucc nargs)))) (funargs (ppred nargs)) (args asm.(parse-args me syntax syn-pat))) asm.(put-insn me.code funargs (pop args)) (while args (let ((x (pop args)) (y (or (pop args) 0))) asm.(put-pair y x))))) (:method dis (me asm funargs arg0) (let ((first t)) (build (add me.symbol) (add (operand-to-sym arg0)) (inc funargs 1) (while (> funargs 0) (dec funargs 2) (tree-bind (y x) asm.(get-pair) (add (if (zap first) x (operand-to-sym x))) (unless (minusp funargs) (add (operand-to-sym y))))))))) (defopcode-derived op-gapply gapply auto op-gcall) (defopcode op-movrs movrs auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (dst src) asm.(parse-args me syntax '(d rs)) asm.(put-insn me.code (enc-small-op src) dst))) (:method dis (me asm src dst) (ignore asm) ^(,me.symbol ,(operand-to-sym dst) ,(small-op-to-sym src)))) (defopcode op-movsr movsr auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (dst src) asm.(parse-args me syntax '(ds r)) asm.(put-insn me.code (enc-small-op dst) src))) (:method dis (me asm dst src) (ignore asm) ^(,me.symbol ,(small-op-to-sym dst) ,(operand-to-sym src)))) (defopcode op-movrr movrr auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (dst src) asm.(parse-args me syntax '(d r)) asm.(put-insn me.code 0 dst) asm.(put-pair 0 src))) (:method dis (me asm extension dst) (ignore asm extension) (let ((src (cadr asm.(get-pair)))) ^(,me.symbol ,(operand-to-sym dst) ,(operand-to-sym src))))) (defopcode op-mov-pseudo mov nil (:method asm (me asm syntax) (tree-bind (dst src) asm.(parse-args me syntax '(d r)) (let ((real [%oc-hash% (cond ((small-op-p dst) 'movsr) ((small-op-p src) 'movrs) (t 'movrr))])) real.(asm asm syntax))))) (defopcode op-jmp jmp auto (:method asm (me asm syntax) me.(chk-arg-count 1 syntax) (let ((dst (car asm.(parse-args me syntax '(l))))) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)))) (:method backpatch (me asm at dst) (ignore at) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))) (:method dis (me asm high16 low16) (ignore asm) ^(,me.symbol ,(logior (ash high16 16) low16)))) (defopcode op-if if auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (reg dst) asm.(parse-args me syntax '(r l)) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)) asm.(put-pair 0 reg))) (:method backpatch (me asm at dst) (ignore at) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))) (:method dis (me asm high16 low16) (ignore asm) (let ((dst (logior (ash high16 16) low16)) (reg (cadr asm.(get-pair)))) ^(,me.symbol ,(operand-to-sym reg) ,dst)))) (defopcode op-ifq ifq auto (:method asm (me asm syntax) me.(chk-arg-count 3 syntax) (tree-bind (lreg rreg dst) asm.(parse-args me syntax '(r r l)) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)) asm.(put-pair lreg rreg))) (:method backpatch (me asm at dst) (ignore at) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))) (:method dis (me asm high16 low16) (let ((dst (logior (ash high16 16) low16))) (tree-bind (lreg rreg) asm.(get-pair) ^(,me.symbol ,(operand-to-sym lreg) ,(operand-to-sym rreg) ,dst))))) (defopcode-derived op-ifql ifql auto op-ifq) (defopcode op-swtch swtch auto (:method asm (me asm syntax) me.(chk-arg-count-min 1 syntax) (let* ((args asm.(parse-args me syntax '(r))) (lbls (cddr syntax)) (tblsz (len lbls))) asm.(put-insn me.code tblsz (car args)) (while lbls (let ((x asm.(lookup-label (pop lbls) %backpatch-low16%)) (y (if lbls asm.(lookup-label (pop lbls) %backpatch-high16%) 0))) asm.(put-pair y x))))) (:method dis (me asm tblsz switch-val) (build (add me.symbol) (add (operand-to-sym switch-val)) (while (> tblsz 0) (dec tblsz 2) (tree-bind (y x) asm.(get-pair) (add x) (unless (minusp tblsz) (add y))))))) (defopcode-derived op-uwprot uwprot auto op-jmp) (defopcode op-block block auto (:method asm (me asm syntax) me.(chk-arg-count 3 syntax) (tree-bind (outreg blname exitpt) asm.(parse-args me syntax '(d r l)) asm.(put-insn me.code (ash exitpt -16) (logtrunc exitpt 16)) asm.(put-pair outreg blname))) (:method backpatch (me asm at exitpt) (ignore at) asm.(put-insn me.code (ash exitpt -16) (logtrunc exitpt 16))) (:method dis (me asm high16 low16) (let ((exitpt (logior (ash high16 16) low16))) (tree-bind (outreg blname) asm.(get-pair) ^(,me.symbol ,(operand-to-sym outreg) ,(operand-to-sym blname) ,exitpt))))) (defopcode op-retsr retsr auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (name reg) asm.(parse-args me syntax '(rs r)) asm.(put-insn me.code (enc-small-op name) reg))) (:method dis (me asm name reg) (ignore asm) ^(,me.symbol ,(small-op-to-sym name) ,(operand-to-sym reg)))) (defopcode op-retrs retrs auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (name reg) asm.(parse-args me syntax '(r rs)) asm.(put-insn me.code (enc-small-op reg) name))) (:method dis (me asm reg name) (ignore asm) ^(,me.symbol ,(operand-to-sym name) ,(small-op-to-sym reg)))) (defopcode op-retrr retrr auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (name reg) asm.(parse-args me syntax '(r r)) asm.(put-insn me.code 0 reg) asm.(put-pair 0 name))) (:method dis (me asm extension reg) (ignore asm extension) (let ((name (cadr asm.(get-pair)))) ^(,me.symbol ,(operand-to-sym name) ,(operand-to-sym reg))))) (defopcode op-ret-pseudo ret nil (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (name reg) asm.(parse-args me syntax '(r r)) (let ((real [%oc-hash% (cond ((small-op-p name) 'retsr) ((small-op-p reg) 'retrs) (t 'retrr))])) real.(asm asm syntax))))) (defopcode-derived op-abscsr abscsr auto op-retsr) (defopcode op-catch catch auto (:method asm (me asm syntax) me.(chk-arg-count 5 syntax) (tree-bind (sym args catch-syms desc dst) asm.(parse-args me syntax '(d d r r l)) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)) asm.(put-pair sym args) asm.(put-pair desc catch-syms))) (:method backpatch (me asm at dst) (ignore at) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))) (:method dis (me asm high16 low16) (ignore asm) (let ((dst (logior (ash high16 16) low16))) (tree-bind (sym args) asm.(get-pair) (tree-bind (desc catch-syms) asm.(get-pair) ^(,me.symbol ,(operand-to-sym sym) ,(operand-to-sym args) ,(operand-to-sym catch-syms) ,(operand-to-sym desc) ,dst)))))) (defopcode op-handle handle auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (fun handle-syms) asm.(parse-args me syntax '(r r)) asm.(put-insn me.code 0 fun) asm.(put-pair fun handle-syms))) (:method dis (me asm extension fun) (ignore asm extension) (let ((handle-syms (cadr asm.(get-pair)))) ^(,me.symbol ,(operand-to-sym fun) ,(operand-to-sym handle-syms))))) (defopcode op-getv getv auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (reg name) asm.(parse-args me syntax '(d r)) (unless (small-op-p name) asm.(asm-one ^(mov (t 1) ,(operand-to-exp name))) (set name 1)) asm.(put-insn me.code (enc-small-op name) reg))) (:method dis (me asm name reg) (ignore asm) ^(,me.symbol ,(operand-to-sym reg) ,(small-op-to-sym name)))) (defopcode-derived op-oldgetf oldgetf auto op-getv) (defopcode-derived op-getl1 getl1 auto op-getv) (defopcode-derived op-getvb getvb auto op-getv) (defopcode-derived op-getfb getfb auto op-getv) (defopcode-derived op-getl1b getl1b auto op-getv) (defopcode op-setv setv auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (reg name) asm.(parse-args me syntax '(r r)) (unless (small-op-p name) asm.(asm-one ^(mov (t 1) ,(operand-to-exp name))) (set name 1)) asm.(put-insn me.code (enc-small-op name) reg))) (:method dis (me asm name reg) (ignore asm) ^(,me.symbol ,(operand-to-sym reg) ,(small-op-to-sym name)))) (defopcode-derived op-setl1 setl1 auto op-setv) (defopcode-derived op-bindv bindv auto op-setv) (defopcode op-close close auto (:method asm (me asm syntax) me.(chk-arg-count-min 6 syntax) (let* ((syn-pat (repeat '(d) (- (length syntax) 7)))) (tree-bind (reg frsize ntreg dst fix req vari . regs) asm.(parse-args me syntax ^(d n n l n n o,*syn-pat)) (unless (<= 0 frsize %lev-size%) me.(synerr "frame size must be 0 to ~a" %lev-size%)) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)) asm.(put-pair (logior (ash (if vari 1 0) %lev-bits%) frsize) reg) asm.(put-pair req fix) asm.(put-pair 0 ntreg) (unless (eql fix (- (len regs) (if vari 1 0))) me.(synerr "wrong number of registers")) (while regs (let ((x (pop regs)) (y (or (pop regs) 0))) asm.(put-pair y x)))))) (:method backpatch (me asm at dst) (ignore at) asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))) (:method dis (me asm high16 low16) (ignore asm) (let ((dst (logior (ash high16 16) low16))) (tree-bind (vari-frsize reg) asm.(get-pair) (let ((vari (bit vari-frsize %lev-bits%))) (tree-bind (req fix) asm.(get-pair) (tree-bind (t ntreg) asm.(get-pair) (build (add me.symbol (operand-to-sym reg) (logtrunc vari-frsize %lev-bits%) ntreg dst fix req vari) (when vari (inc fix)) (while (> fix 0) (dec fix 2) (tree-bind (y x) asm.(get-pair) (add (operand-to-sym x)) (unless (minusp fix) (add (operand-to-sym y))))))))))))) (defopcode op-getlx getlx auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (dst idx) asm.(parse-args me syntax '(d n)) (cond ((small-op-p dst) asm.(put-insn me.code (enc-small-op dst) idx)) (t asm.(put-insn me.code (enc-small-op 1) idx) asm.(asm-one ^(mov ,(operand-to-exp dst) t1)))))) (:method dis (me asm dst idx) (ignore asm) ^(,me.symbol ,(small-op-to-sym dst) ,idx))) (defopcode op-setlx setlx auto (:method asm (me asm syntax) me.(chk-arg-count 2 syntax) (tree-bind (src idx) asm.(parse-args me syntax '(r n)) (cond ((small-op-p src) asm.(put-insn me.code (enc-small-op src) idx)) (t asm.(asm-one ^(mov t1 ,(operand-to-exp src))) asm.(put-insn me.code (enc-small-op 1) idx))))) (:method dis (me asm src idx) (ignore asm) ^(,me.symbol ,(small-op-to-sym src) ,idx))) (defopcode-derived op-getf getf auto op-getlx) (defun disassemble-cdf (code data funv *stdout*) (let ((asm (new assembler buf code))) (put-line "data:") (mapdo (do format t "~5d: ~s\n" @1 @2) (range 0) data) (put-line "syms:") (mapdo (do format t "~5d: ~s\n" @1 @2) (range 0) funv) (put-line "code:") (let ((ninsn asm.(dis-listing))) (put-line "instruction count:") (format t "~5d\n" ninsn)))) (defun disassemble (obj : (stream *stdout*)) (symacrolet ((self 'vm-disassemble-obj)) (typecase obj (vm-desc (disassemble-cdf (vm-desc-bytecode obj) (vm-desc-datavec obj) (vm-desc-symvec obj) stream)) (fun (unless (vm-fun-p obj) (error "~s: not a vm function: ~s" self obj)) (let* ((clo (func-get-env obj)) (desc (sys:vm-closure-desc clo)) (ip (sys:vm-closure-entry clo))) (disassemble desc stream) (put-line "entry point:") (format stream "~5d\n" ip))) (t (iflet ((fun (symbol-function obj))) (disassemble fun stream) (error "~s: not a compiled object: ~s" self obj)))) obj))