1 ;;;; the VOPs and other necessary machine specific support
2 ;;;; routines for call-out to C
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
15 ;; The MOVE-ARG vop is going to store args on the stack for
16 ;; call-out. These tn's will be used for that. move-arg is normally
17 ;; used for things going down the stack but C wants to have args
18 ;; indexed in the positive direction.
20 (defun my-make-wired-tn (prim-type-name sc-name offset
)
21 (make-wired-tn (primitive-type-or-lose prim-type-name
)
22 (sc-number-or-lose sc-name
)
25 (defstruct (arg-state (:copier nil
))
28 (define-alien-type-method (integer :arg-tn
) (type state
)
29 (let ((stack-frame-size (arg-state-stack-frame-size state
)))
30 (setf (arg-state-stack-frame-size state
) (1+ stack-frame-size
))
31 (multiple-value-bind (ptype stack-sc
)
32 (if (alien-integer-type-signed type
)
33 (values 'signed-byte-32
'signed-stack
)
34 (values 'unsigned-byte-32
'unsigned-stack
))
35 (my-make-wired-tn ptype stack-sc stack-frame-size
))))
37 (define-alien-type-method (system-area-pointer :arg-tn
) (type state
)
38 (declare (ignore type
))
39 (let ((stack-frame-size (arg-state-stack-frame-size state
)))
40 (setf (arg-state-stack-frame-size state
) (1+ stack-frame-size
))
41 (my-make-wired-tn 'system-area-pointer
46 (define-alien-type-method (long-float :arg-tn
) (type state
)
47 (declare (ignore type
))
48 (let ((stack-frame-size (arg-state-stack-frame-size state
)))
49 (setf (arg-state-stack-frame-size state
) (+ stack-frame-size
3))
50 (my-make-wired-tn 'long-float
'long-stack stack-frame-size
)))
52 (define-alien-type-method (double-float :arg-tn
) (type state
)
53 (declare (ignore type
))
54 (let ((stack-frame-size (arg-state-stack-frame-size state
)))
55 (setf (arg-state-stack-frame-size state
) (+ stack-frame-size
2))
56 (my-make-wired-tn 'double-float
'double-stack stack-frame-size
)))
58 (define-alien-type-method (single-float :arg-tn
) (type state
)
59 (declare (ignore type
))
60 (let ((stack-frame-size (arg-state-stack-frame-size state
)))
61 (setf (arg-state-stack-frame-size state
) (1+ stack-frame-size
))
62 (my-make-wired-tn 'single-float
'single-stack stack-frame-size
)))
64 (defstruct (result-state (:copier nil
))
67 (defun result-reg-offset (slot)
72 (define-alien-type-method (integer :result-tn
) (type state
)
73 (let ((num-results (result-state-num-results state
)))
74 (setf (result-state-num-results state
) (1+ num-results
))
75 (multiple-value-bind (ptype reg-sc
)
76 (if (alien-integer-type-signed type
)
77 (values 'signed-byte-32
'signed-reg
)
78 (values 'unsigned-byte-32
'unsigned-reg
))
79 (my-make-wired-tn ptype reg-sc
(result-reg-offset num-results
)))))
81 (define-alien-type-method (system-area-pointer :result-tn
) (type state
)
82 (declare (ignore type
))
83 (let ((num-results (result-state-num-results state
)))
84 (setf (result-state-num-results state
) (1+ num-results
))
85 (my-make-wired-tn 'system-area-pointer
'sap-reg
86 (result-reg-offset num-results
))))
89 (define-alien-type-method (long-float :result-tn
) (type state
)
90 (declare (ignore type
))
91 (let ((num-results (result-state-num-results state
)))
92 (setf (result-state-num-results state
) (1+ num-results
))
93 (my-make-wired-tn 'long-float
'long-reg
(* num-results
2))))
95 (define-alien-type-method (double-float :result-tn
) (type state
)
96 (declare (ignore type
))
97 (let ((num-results (result-state-num-results state
)))
98 (setf (result-state-num-results state
) (1+ num-results
))
99 (my-make-wired-tn 'double-float
'double-reg
(* num-results
2))))
101 (define-alien-type-method (single-float :result-tn
) (type state
)
102 (declare (ignore type
))
103 (let ((num-results (result-state-num-results state
)))
104 (setf (result-state-num-results state
) (1+ num-results
))
105 (my-make-wired-tn 'single-float
'single-reg
(* num-results
2))))
107 (define-alien-type-method (values :result-tn
) (type state
)
108 (let ((values (alien-values-type-values type
)))
109 (when (> (length values
) 2)
110 (error "Too many result values from c-call."))
111 (mapcar (lambda (type)
112 (invoke-alien-type-method :result-tn type state
))
115 (!def-vm-support-routine make-call-out-tns
(type)
116 (let ((arg-state (make-arg-state)))
118 (dolist (arg-type (alien-fun-type-arg-types type
))
119 (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state
)))
120 (values (my-make-wired-tn 'positive-fixnum
'any-reg esp-offset
)
121 (* (arg-state-stack-frame-size arg-state
) n-word-bytes
)
123 (invoke-alien-type-method :result-tn
124 (alien-fun-type-result-type type
)
125 (make-result-state))))))
128 (deftransform %alien-funcall
((function type
&rest args
) * * :node node
)
129 (aver (sb!c
::constant-lvar-p type
))
130 (let* ((type (sb!c
::lvar-value type
))
131 (env (sb!c
::node-lexenv node
))
132 (arg-types (alien-fun-type-arg-types type
))
133 (result-type (alien-fun-type-result-type type
)))
134 (aver (= (length arg-types
) (length args
)))
135 (if (or (some #'(lambda (type)
136 (and (alien-integer-type-p type
)
137 (> (sb!alien
::alien-integer-type-bits type
) 32)))
139 (and (alien-integer-type-p result-type
)
140 (> (sb!alien
::alien-integer-type-bits result-type
) 32)))
141 (collect ((new-args) (lambda-vars) (new-arg-types))
142 (dolist (type arg-types
)
143 (let ((arg (gensym)))
145 (cond ((and (alien-integer-type-p type
)
146 (> (sb!alien
::alien-integer-type-bits type
) 32))
147 (new-args `(logand ,arg
#xffffffff
))
148 (new-args `(ash ,arg -
32))
149 (new-arg-types (parse-alien-type '(unsigned 32) env
))
150 (if (alien-integer-type-signed type
)
151 (new-arg-types (parse-alien-type '(signed 32) env
))
152 (new-arg-types (parse-alien-type '(unsigned 32) env
))))
155 (new-arg-types type
)))))
156 (cond ((and (alien-integer-type-p result-type
)
157 (> (sb!alien
::alien-integer-type-bits result-type
) 32))
158 (let ((new-result-type
159 (let ((sb!alien
::*values-type-okay
* t
))
161 (if (alien-integer-type-signed result-type
)
162 '(values (unsigned 32) (signed 32))
163 '(values (unsigned 32) (unsigned 32)))
165 `(lambda (function type
,@(lambda-vars))
166 (declare (ignore type
))
167 (multiple-value-bind (low high
)
168 (%alien-funcall function
169 ',(make-alien-fun-type
170 :arg-types
(new-arg-types)
171 :result-type new-result-type
)
173 (logior low
(ash high
32))))))
175 `(lambda (function type
,@(lambda-vars))
176 (declare (ignore type
))
177 (%alien-funcall function
178 ',(make-alien-fun-type
179 :arg-types
(new-arg-types)
180 :result-type result-type
)
182 (sb!c
::give-up-ir1-transform
))))
184 (define-vop (foreign-symbol-address)
185 (:translate foreign-symbol-address
)
188 (:arg-types
(:constant simple-base-string
))
189 (:info foreign-symbol
)
190 (:results
(res :scs
(sap-reg)))
191 (:result-types system-area-pointer
)
193 (inst lea res
(make-fixup (extern-alien-name foreign-symbol
) :foreign
))))
196 (define-vop (foreign-symbol-dataref-address)
197 (:translate foreign-symbol-dataref-address
)
200 (:arg-types
(:constant simple-string
))
201 (:info foreign-symbol
)
202 (:results
(res :scs
(sap-reg)))
203 (:result-types system-area-pointer
)
205 (inst mov res
(make-fixup (extern-alien-name foreign-symbol
) :foreign-dataref
))))
207 (define-vop (call-out)
208 (:args
(function :scs
(sap-reg))
210 (:results
(results :more t
))
211 (:temporary
(:sc unsigned-reg
:offset eax-offset
212 :from
:eval
:to
:result
) eax
)
213 (:temporary
(:sc unsigned-reg
:offset ecx-offset
214 :from
:eval
:to
:result
) ecx
)
215 (:temporary
(:sc unsigned-reg
:offset edx-offset
216 :from
:eval
:to
:result
) edx
)
220 (:ignore args ecx edx
)
222 (cond ((policy node
(> space speed
))
224 (inst call
(make-fixup (extern-alien-name "call_into_c") :foreign
)))
226 ;; Setup the NPX for C; all the FP registers need to be
227 ;; empty; pop them all.
232 ;; To give the debugger a clue. XX not really internal-error?
233 (note-this-location vop
:internal-error
)
235 ;; Restore the NPX for lisp; ensure no regs are empty
240 (location= (tn-ref-tn results
) fr0-tn
))
241 ;; The return result is in fr0.
242 (inst fxch fr7-tn
) ; move the result back to fr0
243 (inst fldz
)) ; insure no regs are empty
246 (define-vop (alloc-number-stack-space)
248 (:results
(result :scs
(sap-reg any-reg
)))
251 (aver (location= result esp-tn
))
252 (when (policy node
(= sb
!c
::float-accuracy
3))
254 (inst fnstcw
(make-ea :word
:base esp-tn
))
256 (inst or
(make-ea :word
:base esp-tn
) #x300
)
257 (inst fldcw
(make-ea :word
:base esp-tn
))
259 (unless (zerop amount
)
260 (let ((delta (logandc2 (+ amount
3) 3)))
261 (inst sub esp-tn delta
)))
262 (move result esp-tn
)))
264 (define-vop (dealloc-number-stack-space)
268 (unless (zerop amount
)
269 (let ((delta (logandc2 (+ amount
3) 3)))
270 (inst add esp-tn delta
)))
271 (when (policy node
(= sb
!c
::float-accuracy
3))
272 (inst fnstcw
(make-ea :word
:base esp-tn
))
274 (inst and
(make-ea :word
:base esp-tn
) #xfeff
)
275 (inst fldcw
(make-ea :word
:base esp-tn
))
277 (inst add esp-tn
4))))
279 (define-vop (alloc-alien-stack-space)
281 #!+sb-thread
(:temporary
(:sc unsigned-reg
) temp
)
282 (:results
(result :scs
(sap-reg any-reg
)))
285 (aver (not (location= result esp-tn
)))
286 (unless (zerop amount
)
287 (let ((delta (logandc2 (+ amount
3) 3)))
291 (static-symbol-offset '*alien-stack
*)
292 (ash symbol-tls-index-slot word-shift
)
293 (- other-pointer-lowtag
))))
294 (inst fs-segment-prefix
)
295 (inst sub
(make-ea :dword
:scale
1 :index temp
) delta
)))
296 (load-tl-symbol-value result
*alien-stack
*))
299 (aver (not (location= result esp-tn
)))
300 (unless (zerop amount
)
301 (let ((delta (logandc2 (+ amount
3) 3)))
302 (inst sub
(make-ea :dword
304 (static-symbol-offset '*alien-stack
*)
305 (ash symbol-value-slot word-shift
)
306 (- other-pointer-lowtag
)))
308 (load-symbol-value result
*alien-stack
*)))
310 (define-vop (dealloc-alien-stack-space)
312 #!+sb-thread
(:temporary
(:sc unsigned-reg
) temp
)
315 (unless (zerop amount
)
316 (let ((delta (logandc2 (+ amount
3) 3)))
320 (static-symbol-offset '*alien-stack
*)
321 (ash symbol-tls-index-slot word-shift
)
322 (- other-pointer-lowtag
))))
323 (inst fs-segment-prefix
)
324 (inst add
(make-ea :dword
:scale
1 :index temp
) delta
))))
327 (unless (zerop amount
)
328 (let ((delta (logandc2 (+ amount
3) 3)))
329 (inst add
(make-ea :dword
331 (static-symbol-offset '*alien-stack
*)
332 (ash symbol-value-slot word-shift
)
333 (- other-pointer-lowtag
)))
336 ;;; these are not strictly part of the c-call convention, but are
337 ;;; needed for the WITH-PRESERVED-POINTERS macro used for "locking
338 ;;; down" lisp objects so that GC won't move them while foreign
339 ;;; functions go to work.
341 (define-vop (push-word-on-c-stack)
342 (:translate push-word-on-c-stack
)
343 (:args
(val :scs
(sap-reg)))
345 (:arg-types system-area-pointer
)
349 (define-vop (pop-words-from-c-stack)
350 (:translate pop-words-from-c-stack
)
352 (:arg-types
(:constant
(unsigned-byte 29)))
356 (inst add esp-tn
(fixnumize number
))))