Update of /project/movitz/cvsroot/movitz In directory common-lisp.net:/tmp/cvs-serv9077
Modified Files: compiler.lisp Log Message: Started support for stack-allocating functions (of dynamic extent). Primary purpose is to evaluate e.g. handler-case without having to cons up a function for each handler.
Date: Mon Jan 3 12:55:05 2005 Author: ffjeld
Index: movitz/compiler.lisp diff -u movitz/compiler.lisp:1.123 movitz/compiler.lisp:1.124 --- movitz/compiler.lisp:1.123 Tue Dec 21 15:23:49 2004 +++ movitz/compiler.lisp Mon Jan 3 12:55:04 2005 @@ -1,6 +1,6 @@ ;;;;------------------------------------------------------------------ ;;;; -;;;; Copyright (C) 2001,2000, 2002-2004, +;;;; Copyright (C) 2001,2000, 2002-2005, ;;;; Department of Computer Science, University of Tromso, Norway ;;;; ;;;; Description: A simple lisp compiler. @@ -8,7 +8,7 @@ ;;;; Created at: Wed Oct 25 12:30:49 2000 ;;;; Distribution: See the accompanying file COPYING. ;;;; -;;;; $Id: compiler.lisp,v 1.123 2004/12/21 14:23:49 ffjeld Exp $ +;;;; $Id: compiler.lisp,v 1.124 2005/01/03 11:55:04 ffjeld Exp $ ;;;; ;;;;------------------------------------------------------------------
@@ -96,7 +96,7 @@ (make-hash-table :test #'eq))
-(defconstant +enter-stack-frame-code+ +(defparameter +enter-stack-frame-code+ '((:pushl :ebp) (:movl :esp :ebp) (:pushl :esi))) @@ -189,6 +189,13 @@ (funobj-env :initarg :funobj-env :accessor funobj-env) + (extent + :initarg :extent + :initform :unused + :accessor movitz-funobj-extent) + (allocation + :initform nil + :accessor movitz-allocation) (entry-protocol :initform :default :initarg :entry-protocol @@ -643,18 +650,30 @@ (:call-lexical (process-binding funobj (second instruction) '(:call))) (:load-lambda - (let ((lambda-binding (second instruction))) + (destructuring-bind (lambda-binding lambda-result-mode capture-env) + (cdr instruction) + (declare (ignore lambda-result-mode)) (assert (eq funobj (binding-funobj lambda-binding)) () "A non-local lambda doesn't make sense. There must be a bug.") - (resolve-sub-funobj funobj (function-binding-funobj lambda-binding)) - (process-binding funobj lambda-binding '(:read)) - ;; This funobj is effectively using every binding that the lambda - ;; is borrowing.. - (map nil (lambda (borrowed-binding) - (process-binding funobj - (borrowed-binding-target borrowed-binding) - '(:read))) - (borrowed-bindings (function-binding-funobj lambda-binding))))) + (let ((lambda-funobj (function-binding-funobj lambda-binding))) + (let ((dynamic-extent (dynamic-extent-allocation capture-env))) + (when dynamic-extent + (let ((dynamic-scope (allocation-env-scope dynamic-extent))) + ;; (warn "Adding ~S to ~S/~S" lambda-funobj dynamic-extent dynamic-scope) + (setf (movitz-funobj-extent lambda-funobj) :dynamic-extent + (movitz-allocation lambda-funobj) dynamic-scope) + (push lambda-funobj + (dynamic-extent-scope-members (allocation-env-scope dynamic-extent))) + (process-binding funobj (base-binding dynamic-scope) '(:read))))) + (resolve-sub-funobj funobj lambda-funobj) + (process-binding funobj lambda-binding '(:read)) + ;; This funobj is effectively using every binding that the lambda + ;; is borrowing.. + (map nil (lambda (borrowed-binding) + (process-binding funobj + (borrowed-binding-target borrowed-binding) + '(:read))) + (borrowed-bindings (function-binding-funobj lambda-binding)))))) (:local-function-init (let ((function-binding (second instruction))) (assert (eq funobj (binding-funobj function-binding)) () @@ -696,6 +715,7 @@ do (pushnew borrowed-binding (getf (binding-lending (borrowed-binding-target borrowed-binding)) :lended-to))) + ;; (warn "old extent: ~S" (movitz-funobj-extent sub-funobj)) (cond ((or (null usage) (null (borrowed-bindings sub-funobj))) @@ -708,12 +728,16 @@ (change-class function-binding 'closure-binding) (setf (movitz-funobj-extent sub-funobj) :lexical-extent)) + ((eq :dynamic-extent (movitz-funobj-extent sub-funobj)) + (change-class function-binding 'closure-binding)) (t (change-class function-binding 'closure-binding) (setf (movitz-funobj-extent sub-funobj) :indefinite-extent))) ; XXX - #+ignore (warn "extent: ~S => ~S" - sub-funobj - (movitz-funobj-extent sub-funobj))))) + #+ignore + (warn "extent usage ~S: ~S => ~S" + usage + sub-funobj + (movitz-funobj-extent sub-funobj))))) (loop for function-binding in function-binding-usage by #'cddr do (finalize-funobj (function-binding-funobj function-binding))) (finalize-funobj toplevel-funobj)) @@ -1003,8 +1027,18 @@ (defun check-locate-concistency (code-vector) (loop for x from 0 below (length code-vector) by 8 do (when (and (= (tag :basic-vector) (aref code-vector x)) - (= (enum-value 'movitz-vector-element-type :code) (aref code-vector (1+ x)))) - (break "Code-vector can break %find-code-vector at offset ~D." x))) + (= (enum-value 'movitz-vector-element-type :code) (aref code-vector (1+ x))) + (or (<= #x4000 (length code-vector)) + (and (= (ldb (byte 8 0) (length code-vector)) + (aref code-vector (+ x 2))) + (= (ldb (byte 8 8) (length code-vector)) + (aref code-vector (+ x 3)))))) + (break "Code-vector (length #x~X) can break %find-code-vector at ~D: #x~2,'0X~2,'0X ~2,'0X~2,'0X." + (length code-vector) x + (aref code-vector (+ x 0)) + (aref code-vector (+ x 1)) + (aref code-vector (+ x 2)) + (aref code-vector (+ x 3))))) (values))
#+ignore @@ -1585,10 +1619,10 @@ (0 nil) (1 (cadr c)) (2 (twop-dst c))))) - (non-destructuve-p (c) + (non-destructive-p (c) (let ((c (ignore-instruction-prefixes c))) (and (consp c) - (member (car c) '(:testl :testb :pushl :cmpl :cmpb :frame-map :std))))) + (member (car c) '(:testl :testb :cmpl :cmpb :frame-map :std))))) (simple-instruction-p (c) (let ((c (ignore-instruction-prefixes c))) (and (listp c) @@ -1627,7 +1661,7 @@ (or (global-funcall-p i) (instruction-is i :frame-map) (branch-instruction-label i) - (non-destructuve-p i) + (non-destructive-p i) (and (simple-instruction-p i) (not (eql stack-location (stack-frame-operand (idst i))))))))) (preserves-register-p (i register) @@ -1637,10 +1671,12 @@ (not (eq register (idst i)))) (instruction-is i :frame-map) (branch-instruction-label i) - (non-destructuve-p i) + (non-destructive-p i) (and (member register '(:edx)) (member (global-funcall-p i) - '(fast-car fast-cdr fast-car-ebx fast-cdr-ebx))))))) + '(fast-car fast-cdr fast-car-ebx fast-cdr-ebx))) + (and (not (eq register :esp)) + (instruction-is i :pushl)))))) (operand-register-indirect-p (operand register) (and (consp operand) (tree-search operand register))) @@ -1811,7 +1847,7 @@ (twop-src ii)) (pushnew (store-stack-frame-p ii) modifieds)) - ((non-destructuve-p ii)) + ((non-destructive-p ii)) ((branch-instruction-label ii)) ((simple-instruction-p ii) (let ((op (idst ii))) @@ -2813,14 +2849,16 @@ (cdr (first init-pc)) (declare (ignore protect-registers protect-carry init-with-type)) (assert (eq binding init-binding)) - (let* ((load-instruction - (find-if (lambda (i) - (and (not (instruction-is i :init-lexvar)) - (member binding (find-read-bindings i) - :test #'binding-eql))) - (cdr init-pc))) - (binding-destination (third load-instruction)) - (distance (position load-instruction (cdr init-pc)))) + (multiple-value-bind (load-instruction binding-destination distance) + (loop for i in (cdr init-pc) as distance upfrom 0 + do (when (not (instruction-is i :init-lexvar)) + (multiple-value-bind (read-bindings read-destinations) + (find-read-bindings i) + (let ((pos (position binding read-bindings :test #'binding-eql))) + (when pos + (return (values i (nth pos read-destinations) distance))))))) + (declare (ignore load-instruction)) + ;; (warn "load: ~S, dist: ~S, dest: ~S" load-instruction distance binding-destination) (multiple-value-bind (free-registers more-later-p) (and distance (compute-free-registers (cdr init-pc) distance funobj frame-map)) (let ((free-registers-no-ecx (remove :ecx free-registers))) @@ -2912,6 +2950,15 @@ ((:local-function-init :load-lambda) (let ((function-binding (second instruction))) (take-note-of-binding function-binding) + (let ((sub-funobj (function-binding-funobj function-binding))) + #+ignore + (warn "fun-ext: ~S ~S ~S" + sub-funobj + (movitz-funobj-extent sub-funobj) + (movitz-allocation sub-funobj)) + (when (typep (movitz-allocation sub-funobj) + 'with-dynamic-extent-scope-env) + (take-note-of-binding (base-binding (movitz-allocation sub-funobj))))) (let ((closure-funobj (function-binding-funobj function-binding))) (dolist (borrowing-binding (borrowed-bindings closure-funobj)) (lend-lexical borrowing-binding nil))))) @@ -3189,6 +3236,11 @@ (:load-lambda (or (when load (binding-eql binding (second instruction))) + (let ((allocation (movitz-allocation + (function-binding-funobj (second instruction))))) + (when (and load + (typep allocation 'with-dynamic-extent-scope-env)) + (binding-eql binding (base-binding allocation)))) (search-funobj (function-binding-funobj (second instruction)) binding load store call))) (:call-lexical @@ -3321,9 +3373,6 @@ code) env stack-frame-position frame-map))
-(defconstant +dynamic-frame-marker+ #xd193) -(defconstant +dynamic-catch-marker+ #xd293) - (defun single-value-register (mode) (ecase mode ((:eax :single-value :multiple-values :function) :eax) @@ -3670,10 +3719,19 @@ (assert (eq funobj-register :edx)) (when (getf (binding-lending lended-binding) :dynamic-extent-p) (assert dynamic-extent-p)) - ;; (warn "lending: ~W" lended-binding) + #+ignore + (warn "lending: ~W: ~S" + lended-binding + (mapcar #'movitz-funobj-extent + (mapcar #'binding-funobj + (getf (binding-lending lended-binding) :lended-to)))) (append (make-load-lexical lended-binding :eax funobj t frame-map) (unless (or (typep lended-binding 'borrowed-binding) - (getf (binding-lending lended-binding) :dynamic-extent-p)) + (getf (binding-lending lended-binding) :dynamic-extent-p) + (every (lambda (borrower) + (member (movitz-funobj-extent (binding-funobj borrower)) + '(:lexical-extent :dynamic-extent))) + (getf (binding-lending lended-binding) :lended-to))) (append `((:pushl :edx) (:globally (:call (:edi (:edi-offset ensure-heap-cons-variable)))) (:popl :edx)) @@ -3754,8 +3812,23 @@ nil) ((typep function-binding 'funobj-binding) nil) - (t (when (null (borrowed-bindings sub-funobj)) - (warn "null lending for ~S" sub-funobj)) + #+ignore + ((member (movitz-funobj-extent sub-funobj) + '(:dynamic-extent :lexical-extent)) + (check-type function-binding closure-binding) + (when (plusp (movitz-funobj-num-jumpers sub-funobj)) + (break "Don't know yet how to stack a funobj with jumpers.")) + (let ((words (+ (movitz-funobj-num-constants sub-funobj) + (/ (sizeof 'movitz-funobj) 4)))) + (break "words for ~S: ~S" words sub-funobj) + (append `((:movl :esp :eax) + (:testl 4 :eax) + (:jz 'no-alignment-needed) + (:pushl :edi) + no-alignment-needed) + (make-load-constant sub-funobj :eax funobj frame-map) + ))) + (t (assert (not (null (borrowed-bindings sub-funobj)))) (append (make-load-constant sub-funobj :eax funobj frame-map) `((:movl (:edi ,(global-constant-offset 'copy-funobj)) :esi) (:call (:esi ,(bt:slot-offset 'movitz-funobj 'code-vector%1op))) @@ -3765,8 +3838,9 @@ append (make-lend-lexical bb :edx nil)))))) funobj frame-map))) (:load-lambda - (destructuring-bind (function-binding register) + (destructuring-bind (function-binding register capture-env) (operands instruction) + (declare (ignore capture-env)) ;; (warn "load-lambda not completed for ~S" function-binding) (finalize-code (let* ((sub-funobj (function-binding-funobj function-binding)) @@ -3777,6 +3851,17 @@ ((null lend-code) ;; (warn "null lambda lending") (append (make-load-constant sub-funobj register funobj frame-map))) + ((typep (movitz-allocation sub-funobj) + 'with-dynamic-extent-scope-env) + (let ((dynamic-scope (movitz-allocation sub-funobj))) + (append (make-load-lexical (base-binding dynamic-scope) :edx + funobj nil frame-map) + `((:leal (:edx ,(tag :other) + ,(dynamic-extent-object-offset dynamic-scope + sub-funobj)) + :edx)) + lend-code + `((:movl :edx ,register))))) (t (append (make-load-constant sub-funobj :eax funobj frame-map) `((:movl (:edi ,(global-constant-offset 'copy-funobj)) :esi) (:call (:esi ,(bt:slot-offset 'movitz-funobj 'code-vector%1op))) @@ -3921,7 +4006,7 @@ `((,op ,(new-make-compiled-constant-reference movitz-obj funobj) ,result-mode))))))))
-(defconstant +movitz-lambda-list-keywords+ +(defparameter +movitz-lambda-list-keywords+ '(muerte.cl:&OPTIONAL muerte.cl:&REST muerte.cl:&KEY @@ -5825,16 +5910,18 @@ (assert (null unwind-protects) () "Lexical unwind-protect not implemented, to-env: ~S. (this is not supposed to happen)" to-env) + ;; (warn "dist: ~S, slots: ~S" stack-distance num-dynamic-slots) (cond ((and (eq t stack-distance) - (zerop num-dynamic-slots)) + (eql 0 num-dynamic-slots)) (compiler-values () :returns :non-local-exit :code (append return-code (unless (eq :function (exit-result-mode to-env)) - `((:load-lexical ,(save-esp-variable to-env) :esp))) + `((:load-lexical ,(movitz-binding (save-esp-variable to-env) to-env nil) :esp))) `((:jmp ',to-label))))) - ((eq t stack-distance) + ((or (eq t stack-distance) + (eq t num-dynamic-slots)) (compiler-values () :returns :non-local-exit :code (append return-code @@ -5850,7 +5937,7 @@ (:locally (:call (:edi (:edi-offset dynamic-unwind-next)))) (:locally (:movl :eax (:edi (:edi-offset dynamic-env)))) (:jc '(:sub-program () (:int 63)))))) - `((:load-lexical ,(save-esp-variable to-env) :esp) + `((:load-lexical ,(movitz-binding (save-esp-variable to-env) to-env nil) :esp) (:jmp ',to-label))))) ((zerop num-dynamic-slots) (compiler-values () @@ -5923,6 +6010,8 @@ (+ x y) t)) (find-stack-delta (env stack-distance num-dynamic-slots unwind-protects) + #+ignore (warn "find-stack-delta: ~S dist ~S, slots ~S" env + (stack-used env) (num-dynamic-slots env)) (cond ((eq outer-env env) ;; Each dynamic-slot is 4 stack-distances, so let's check that.. @@ -5935,7 +6024,7 @@ (values nil 0 nil)) (t (find-stack-delta (movitz-environment-uplink env) (stack-distance-add stack-distance (stack-used env)) - (+ num-dynamic-slots (num-dynamic-slots env)) + (stack-distance-add num-dynamic-slots (num-dynamic-slots env)) (if (typep env 'unwind-protect-env) (cons env unwind-protects) unwind-protects)))))) @@ -6000,9 +6089,7 @@ (let* ((operator (car extended-instruction)) (finder (gethash operator *extended-code-find-read-binding*))) (when finder - (let ((result (funcall finder extended-instruction))) - (check-type result list "a list of read bindings") - result))))) + (funcall finder extended-instruction)))))
(defmacro define-find-write-binding-and-type (name lambda-list &body body) (let ((defun-name (intern @@ -6098,9 +6185,9 @@ (list source)))))
(define-find-read-bindings :load-lexical (source destination &key &allow-other-keys) - (declare (ignore destination)) (check-type source binding) - (list source)) + (values (list source) + (list destination)))
(define-extended-code-expander :load-lexical (instruction funobj frame-map) (destructuring-bind (source destination &key shared-reference-p tmp-register protect-registers) @@ -6781,3 +6868,67 @@ (:call (:esi ,(bt:slot-offset 'movitz-funobj 'code-vector%2op))) ,eql-done)))) (t (error "unknown eql: ~S" instruction)))))))) + +(define-find-read-bindings :load-lambda (lambda-binding result-mode capture-env) + (declare (ignore result-mode capture-env)) + (let ((allocation (movitz-allocation (function-binding-funobj lambda-binding)))) + (when (typep allocation 'with-dynamic-extent-scope-env) + (values (list (base-binding allocation)) + (list :edx))))) + +(define-find-write-binding-and-type :enter-dynamic-scope (instruction) + (destructuring-bind (scope-env) + (cdr instruction) + (if (null (dynamic-extent-scope-members scope-env)) + (values nil) + (values (base-binding scope-env) 'fixnum)))) + +(define-extended-code-expander :enter-dynamic-scope (instruction funobj frame-map) + (declare (ignore funobj frame-map)) + (destructuring-bind (scope-env) + (cdr instruction) + (if (null (dynamic-extent-scope-members scope-env)) + nil + (append `((:pushl :edi) + (:movl :esp :eax) + (:andl 4 :eax) + (:addl :eax :esp)) + (loop for object in (reverse (dynamic-extent-scope-members scope-env)) + appending + (etypecase object + (movitz-funobj + (append (unless (zerop (mod (sizeof object) 8)) + `((:pushl :edi))) + `((:load-constant ,object :eax)) + (loop for i from (1- (movitz-funobj-num-constants object)) + downto (movitz-funobj-num-jumpers object) + collect `(:pushl (:eax ,(slot-offset 'movitz-funobj 'constant0) + ,(* 4 i)))) + (loop repeat (movitz-funobj-num-jumpers object) + do (error "Can't handle jumpers.") + collect `(:pushl 0)) + `((:pushl (:eax ,(slot-offset 'movitz-funobj 'num-jumpers))) + (:pushl (:eax ,(slot-offset 'movitz-funobj 'name))) + (:pushl (:eax ,(slot-offset 'movitz-funobj 'lambda-list))) + +;;; (:pushl 0) ; %3op +;;; (:pushl 0) ; %2op +;;; (:pushl 0) ; %1op +;;; (:pushl 0) ; (default) + (:pushl (:eax ,(slot-offset 'movitz-funobj 'code-vector%3op))) + (:pushl (:eax ,(slot-offset 'movitz-funobj 'code-vector%2op))) + (:pushl (:eax ,(slot-offset 'movitz-funobj 'code-vector%1op))) + (:pushl (:eax ,(slot-offset 'movitz-funobj 'code-vector))) + + (:pushl (:eax ,(slot-offset 'movitz-funobj 'type)))))))))))) + +;;;(define-extended-code-expander :exit-dynamic-scope (instruction funobj frame-map) +;;; nil) + +(define-find-read-bindings :lexical-control-transfer (return-code return-mode from-env to-env + &optional to-label) + (declare (ignore return-code return-mode to-label)) + (let ((distance (stack-delta from-env to-env))) + (when (eq t distance) + (values (list (movitz-binding (save-esp-variable to-env) to-env nil)) + (list :esp)))))