1.0.5.25:
[sbcl.git] / src / runtime / x86-assem.S
1 /*
2  * very-low-level utilities for runtime support
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15 \f
16 #define LANGUAGE_ASSEMBLY
17 #include "sbcl.h"
18 #include "validate.h"
19 #include "genesis/closure.h"
20 #include "genesis/funcallable-instance.h"
21 #include "genesis/fdefn.h"
22 #include "genesis/static-symbols.h"
23 #include "genesis/symbol.h"
24 #include "genesis/thread.h"
25         
26 /* Minimize conditionalization for different OS naming schemes. 
27  *
28  * (As of sbcl-0.8.10, this seems no longer to be much of an issue, 
29  * since everyone has converged on ELF. If this generality really 
30  * turns out not to matter, perhaps it's just clutter we could get
31  * rid of? -- WHN 2004-04-18)
32  *
33  * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
34  */
35 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
36 #define GNAME(var) var
37 #else
38 #define GNAME(var) _##var
39 #endif
40
41 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
42  * want alignment in bytes. 
43  *
44  * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems 
45  * no longer to be much of an issue, since everyone has converged on
46  * the same value. If this generality really turns out not to 
47  * matter any more, perhaps it's just clutter we could get
48  * rid of? -- WHN 2004-04-18)
49  */
50 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(LISP_FEATURE_WIN32)
51 #define align_4byte     4
52 #define align_8byte     8
53 #define align_16byte    16
54 #else
55 #define align_4byte     2
56 #define align_8byte     3
57 #define align_16byte    4       
58 #endif                  
59
60 /*
61  * The assembler used for win32 doesn't like .type or .size directives,
62  * so we want to conditionally kill them out. So let's wrap them in macros
63  * that are defined to be no-ops on win32. Hopefully this still works on
64  * other platforms.
65  */
66 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
67 #define TYPE(name) .type name,@function
68 #define SIZE(name) .size name,.-name
69 #else
70 #define TYPE(name)
71 #define SIZE(name)
72 #endif
73
74 /*
75  * x86/darwin (as of MacOS X 10.4.5) doesn't reliably file signal
76  * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
77  * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
78  * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
79  * for this instruction in the SIGILL handler and if we see it, we
80  * advance the EIP by two bytes to skip over ud2 instruction and
81  * call sigtrap_handler. */
82 #if defined(LISP_FEATURE_DARWIN)
83 #define END()
84 #define TRAP ud2
85 #else
86 #define END() .end
87 #define TRAP int3
88 #endif
89
90         .text
91         .globl  GNAME(all_threads)
92 \f
93 /*
94  * A call to call_into_c preserves esi, edi, and ebp.   
95  * (The C function will preserve ebx, esi, edi, and ebp across its
96  * function call, but we trash ebx ourselves by using it to save the
97  * return Lisp address.)
98  *
99  * Return values are in eax and maybe edx for quads, or st(0) for
100  * floats.
101  *
102  * This should work for Lisp calls C calls Lisp calls C..
103  *
104  * FIXME & OAOOM: This duplicates call-out in src/compiler/x86/c-call.lisp,
105  * so if you tweak this, change that too!
106  */
107         .text
108         .align  align_16byte,0x90
109         .globl GNAME(call_into_c)
110         TYPE(GNAME(call_into_c))
111 GNAME(call_into_c):
112 /* Save the return Lisp address in ebx. */
113         popl    %ebx
114
115 /* Setup the NPX for C */
116         fstp    %st(0)
117         fstp    %st(0)
118         fstp    %st(0)
119         fstp    %st(0)
120         fstp    %st(0)
121         fstp    %st(0)
122         fstp    %st(0)
123         fstp    %st(0)
124
125 #ifdef LISP_FEATURE_WIN32
126         cld
127 #endif
128
129 #ifdef LISP_FEATURE_DARWIN
130         andl    $0xfffffff0,%esp        # align stack to 16-byte boundary before calling C
131 #endif
132         call    *%eax           # normal callout using Lisp stack
133
134         movl    %eax,%ecx       # remember integer return value
135
136 /* Check for a return FP value. */
137         fxam
138         fnstsw  %eax
139         andl    $0x4500,%eax
140         cmpl    $0x4100,%eax
141         jne     Lfp_rtn_value
142
143 /* The return value is in eax, or eax,edx? */
144 /* Set up the NPX stack for Lisp. */
145         fldz                    # Ensure no regs are empty.
146         fldz
147         fldz
148         fldz
149         fldz
150         fldz
151         fldz
152         fldz
153
154 /* Restore the return value. */
155         movl    %ecx,%eax       # maybe return value
156
157 /* Return. */
158         jmp     *%ebx
159
160 Lfp_rtn_value:
161 /* The return result is in st(0). */
162 /* Set up the NPX stack for Lisp, placing the result in st(0). */
163         fldz                    # Ensure no regs are empty.
164         fldz
165         fldz
166         fldz
167         fldz
168         fldz
169         fldz
170         fxch    %st(7)          # Move the result back to st(0).
171
172 /* We don't need to restore eax, because the result is in st(0). */
173
174 /* Return. */   
175         jmp     *%ebx
176
177         SIZE(GNAME(call_into_c))
178
179 \f
180         .text   
181         .globl GNAME(call_into_lisp_first_time)
182         TYPE(GNAME(call_into_lisp_first_time))
183                 
184 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
185  * the stack changes.  We don't worry too much about saving registers 
186  * here, because we never expect to return from the initial call to lisp 
187  * anyway */
188         
189         .align  align_16byte,0x90
190 GNAME(call_into_lisp_first_time):
191         pushl   %ebp            # Save old frame pointer.
192         movl    %esp,%ebp       # Establish new frame.
193 #ifndef LISP_FEATURE_WIN32
194         movl    %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
195         movl    GNAME(all_threads),%eax
196         movl    THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
197         /* don't think too hard about what happens if we get interrupted
198         * here */
199         addl    $(THREAD_CONTROL_STACK_SIZE),%esp
200 #else
201 /* Win32 -really- doesn't like you switching stacks out from under it. */
202         movl    GNAME(all_threads),%eax
203 #endif
204         jmp     Lstack
205 \f
206         .text   
207         .globl GNAME(call_into_lisp)
208         TYPE(GNAME(call_into_lisp))
209                 
210 /* The C conventions require that ebx, esi, edi, and ebp be preserved
211  * across function calls. */
212         
213         .align  align_16byte,0x90
214 GNAME(call_into_lisp):
215         pushl   %ebp            # Save old frame pointer.
216         movl    %esp,%ebp       # Establish new frame.
217 Lstack:
218 /* Save the NPX state */
219         fwait                   # Catch any pending NPX exceptions.
220         subl    $108,%esp       # Make room for the NPX state.
221         fnsave  (%esp)          # save and reset NPX
222
223         movl    (%esp),%eax     # Load NPX control word.
224         andl    $0xfffff2ff,%eax        # Set rounding mode to nearest.
225         orl     $0x00000200,%eax        # Set precision to 64 bits.  (53-bit mantissa)
226         pushl   %eax
227         fldcw   (%esp)          # Recover modes.
228         popl    %eax
229
230         fldz                    # Ensure no FP regs are empty.
231         fldz
232         fldz
233         fldz
234         fldz
235         fldz
236         fldz
237         fldz
238         
239 /* Save C regs: ebx esi edi. */
240         pushl   %ebx
241         pushl   %esi
242         pushl   %edi
243         
244 /* Clear descriptor regs. */
245         xorl    %eax,%eax       # lexenv
246         xorl    %ebx,%ebx       # available
247         xorl    %ecx,%ecx       # arg count
248         xorl    %edx,%edx       # first arg
249         xorl    %edi,%edi       # second arg
250         xorl    %esi,%esi       # third arg
251
252 /* no longer in function call */
253         movl    %esp,%ebx       # remember current stack
254         pushl   %ebx            # Save entry stack on (maybe) new stack.
255
256         /* Establish Lisp args. */
257         movl     8(%ebp),%eax   # lexenv?
258         movl    12(%ebp),%ebx   # address of arg vec
259         movl    16(%ebp),%ecx   # num args
260         shll    $2,%ecx         # Make num args into fixnum.
261         cmpl    $0,%ecx
262         je      Ldone
263         movl    (%ebx),%edx     # arg0
264         cmpl    $4,%ecx
265         je      Ldone
266         movl    4(%ebx),%edi    # arg1
267         cmpl    $8,%ecx
268         je      Ldone
269         movl    8(%ebx),%esi    # arg2
270 Ldone:  
271         /* Registers eax, ecx, edx, edi, and esi are now live. */
272
273 #ifdef LISP_FEATURE_WIN32
274         /* Establish an SEH frame. */
275 #ifdef LISP_FEATURE_SB_THREAD
276         /* FIXME: need to save BSP here. */
277 #error "need to save BSP here, but don't know how yet."
278 #else
279         pushl   BINDING_STACK_POINTER + SYMBOL_VALUE_OFFSET
280 #endif
281         pushl   $GNAME(exception_handler_wrapper)
282         pushl   %fs:0
283         movl    %esp, %fs:0
284 #endif
285
286         /* Alloc new frame. */
287         mov     %esp,%ebx       # The current sp marks start of new frame.
288         push    %ebp            # fp in save location S0
289         sub     $8,%esp         # Ensure 3 slots are allocated, one above.
290         mov     %ebx,%ebp       # Switch to new frame.
291
292         call    *CLOSURE_FUN_OFFSET(%eax)
293         
294         /* If the function returned multiple values, it will return to
295            this point.  Lose them */
296         jnc     LsingleValue
297         mov     %ebx, %esp
298 LsingleValue:
299         /* A singled value function returns here */
300
301 #ifdef LISP_FEATURE_WIN32
302         /* Remove our SEH frame. */
303         popl    %fs:0
304         add     $8, %esp
305 #endif
306
307 /* Restore the stack, in case there was a stack change. */
308         popl    %esp            # c-sp
309
310 /* Restore C regs: ebx esi edi. */
311         popl    %edi
312         popl    %esi
313         popl    %ebx
314
315 /* Restore the NPX state. */
316         frstor  (%esp)
317         addl    $108, %esp
318         
319         popl    %ebp            # c-sp
320         movl    %edx,%eax       # c-val
321         ret
322         SIZE(GNAME(call_into_lisp))
323 \f
324 /* support for saving and restoring the NPX state from C */
325         .text
326         .globl  GNAME(fpu_save)
327         TYPE(GNAME(fpu_save))
328         .align  2,0x90
329 GNAME(fpu_save):
330         movl    4(%esp),%eax
331         fnsave  (%eax)          # Save the NPX state. (resets NPX)
332         ret
333         SIZE(GNAME(fpu_save))
334
335         .globl  GNAME(fpu_restore)
336         TYPE(GNAME(fpu_restore))
337         .align  2,0x90
338 GNAME(fpu_restore):
339         movl    4(%esp),%eax
340         frstor  (%eax)          # Restore the NPX state.
341         ret
342         SIZE(GNAME(fpu_restore))
343 \f
344 /*
345  * the undefined-function trampoline
346  */
347         .text
348         .align  align_4byte,0x90
349         .globl GNAME(undefined_tramp)
350         TYPE(GNAME(undefined_tramp))
351         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
352 GNAME(undefined_tramp):
353         TRAP
354         .byte   trap_Error
355         .byte   2
356         .byte   UNDEFINED_FUN_ERROR
357         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
358         ret
359         SIZE(GNAME(undefined_tramp))
360
361 /*
362  * the closure trampoline
363  */
364         .text
365         .align  align_4byte,0x90
366         .globl GNAME(closure_tramp)
367         TYPE(GNAME(closure_tramp))
368         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
369 GNAME(closure_tramp):
370         movl    FDEFN_FUN_OFFSET(%eax),%eax
371         /* FIXME: The '*' after "jmp" in the next line is from PVE's
372          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
373          * reasonable, and it certainly seems as though if CMU CL needs it,
374          * SBCL needs it too, but I haven't actually verified that it's
375          * right. It would be good to find a way to force the flow of
376          * control through here to test it. */
377         jmp     *CLOSURE_FUN_OFFSET(%eax)
378         SIZE(GNAME(closure_tramp))
379
380         .text
381         .align  align_4byte,0x90
382         .globl GNAME(funcallable_instance_tramp)
383         TYPE(GNAME(funcallable_instance_tramp))
384 GNAME(funcallable_instance_tramp):
385         movl    FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(%eax),%eax 
386         /* KLUDGE: on this platform, whatever kind of function is in %rax
387          * now, the first word of it contains the address to jump to. */
388         jmp     *CLOSURE_FUN_OFFSET(%eax)
389         SIZE(GNAME(funcallable_instance_tramp))
390         
391 /*
392  * fun-end breakpoint magic
393  */
394         .text
395         .globl  GNAME(fun_end_breakpoint_guts)
396         .align  align_4byte
397 GNAME(fun_end_breakpoint_guts):
398         /* Multiple Value return */
399         jc      multiple_value_return
400         /* Single value return: The eventual return will now use the
401            multiple values return convention but with a return values
402            count of one. */
403         movl    %esp,%ebx       # Setup ebx - the ofp.
404         subl    $4,%esp         # Allocate one stack slot for the return value
405         movl    $4,%ecx         # Setup ecx for one return value.
406         movl    $(NIL),%edi     # default second value
407         movl    $(NIL),%esi     # default third value
408                 
409 multiple_value_return:
410         
411         .globl GNAME(fun_end_breakpoint_trap)
412 GNAME(fun_end_breakpoint_trap):
413         TRAP
414         .byte   trap_FunEndBreakpoint
415         hlt                     # We should never return here.
416
417         .globl GNAME(fun_end_breakpoint_end)
418 GNAME(fun_end_breakpoint_end):
419
420 \f
421         .globl  GNAME(do_pending_interrupt)
422         TYPE(GNAME(do_pending_interrupt))
423         .align  align_4byte,0x90
424 GNAME(do_pending_interrupt):
425         TRAP
426         .byte   trap_PendingInterrupt
427         ret
428         SIZE(GNAME(do_pending_interrupt))
429 \f
430
431 /*
432  * Allocate bytes and return the start of the allocated space
433  * in the specified destination register.
434  *
435  * In the general case the size will be in the destination register.
436  *
437  * All registers must be preserved except the destination.
438  * The C conventions will preserve ebx, esi, edi, and ebp.
439  * So only eax, ecx, and edx need special care here.
440  */
441         
442         .globl  GNAME(alloc_to_eax)
443         TYPE(GNAME(alloc_to_eax))
444         .align  align_4byte,0x90
445 GNAME(alloc_to_eax):
446         pushl   %ecx    # Save ecx and edx as C could destroy them.
447         pushl   %edx
448         pushl   %eax    # Push the size.
449         call    GNAME(alloc)
450         addl    $4,%esp # Pop the size arg.
451         popl    %edx    # Restore ecx and edx.
452         popl    %ecx
453         ret
454         SIZE(GNAME(alloc_to_eax))
455
456         .globl  GNAME(alloc_8_to_eax)
457         TYPE(GNAME(alloc_8_to_eax))
458         .align  align_4byte,0x90
459 GNAME(alloc_8_to_eax):
460         pushl   %ecx    # Save ecx and edx as C could destroy them.
461         pushl   %edx
462         pushl   $8      # Push the size.
463         call    GNAME(alloc)
464         addl    $4,%esp # Pop the size arg.
465         popl    %edx    # Restore ecx and edx.
466         popl    %ecx
467         ret
468         SIZE(GNAME(alloc_8_to_eax))
469
470         .globl  GNAME(alloc_8_to_eax)
471         TYPE(GNAME(alloc_8_to_eax))
472         .align  align_4byte,0x90
473
474         .globl  GNAME(alloc_16_to_eax)
475         TYPE(GNAME(alloc_16_to_eax))
476         .align  align_4byte,0x90
477 GNAME(alloc_16_to_eax):
478         pushl   %ecx    # Save ecx and edx as C could destroy them.
479         pushl   %edx
480         pushl   $16     # Push the size.
481         call    GNAME(alloc)
482         addl    $4,%esp # Pop the size arg.
483         popl    %edx    # Restore ecx and edx.
484         popl    %ecx
485         ret
486         SIZE(GNAME(alloc_16_to_eax))
487
488         .globl  GNAME(alloc_to_ecx)
489         TYPE(GNAME(alloc_to_ecx))
490         .align  align_4byte,0x90
491 GNAME(alloc_to_ecx):
492         pushl   %eax    # Save eax and edx as C could destroy them.
493         pushl   %edx
494         pushl   %ecx    # Push the size.
495         call    GNAME(alloc)
496         addl    $4,%esp # Pop the size arg.
497         movl    %eax,%ecx       # Set up the destination.
498         popl    %edx    # Restore eax and edx.
499         popl    %eax
500         ret
501         SIZE(GNAME(alloc_to_ecx))
502
503         .globl  GNAME(alloc_8_to_ecx)
504         TYPE(GNAME(alloc_8_to_ecx))
505         .align  align_4byte,0x90
506 GNAME(alloc_8_to_ecx):
507         pushl   %eax    # Save eax and edx as C could destroy them.
508         pushl   %edx
509         pushl   $8      # Push the size.
510         call    GNAME(alloc)
511         addl    $4,%esp # Pop the size arg.
512         movl    %eax,%ecx       # Set up the destination.
513         popl    %edx    # Restore eax and edx.
514         popl    %eax
515         ret
516         SIZE(GNAME(alloc_8_to_ecx))
517
518         .globl  GNAME(alloc_16_to_ecx)
519         TYPE(GNAME(alloc_16_to_ecx))
520         .align  align_4byte,0x90
521 GNAME(alloc_16_to_ecx):
522         pushl   %eax    # Save eax and edx as C could destroy them.
523         pushl   %edx
524         pushl   $16     # Push the size.
525         call    GNAME(alloc)
526         addl    $4,%esp # Pop the size arg.
527         movl    %eax,%ecx       # Set up the destination.
528         popl    %edx    # Restore eax and edx.
529         popl    %eax
530         ret
531         SIZE(GNAME(alloc_16_to_ecx))
532
533
534         .globl  GNAME(alloc_to_edx)
535         TYPE(GNAME(alloc_to_edx))
536         .align  align_4byte,0x90
537 GNAME(alloc_to_edx):
538         pushl   %eax    # Save eax and ecx as C could destroy them.
539         pushl   %ecx
540         pushl   %edx    # Push the size.
541         call    GNAME(alloc)
542         addl    $4,%esp # Pop the size arg.
543         movl    %eax,%edx       # Set up the destination.
544         popl    %ecx    # Restore eax and ecx.
545         popl    %eax
546         ret
547         SIZE(GNAME(alloc_to_edx))
548
549         .globl  GNAME(alloc_8_to_edx)
550         TYPE(GNAME(alloc_8_to_edx))
551         .align  align_4byte,0x90
552 GNAME(alloc_8_to_edx):
553         pushl   %eax    # Save eax and ecx as C could destroy them.
554         pushl   %ecx
555         pushl   $8      # Push the size.
556         call    GNAME(alloc)
557         addl    $4,%esp # Pop the size arg.
558         movl    %eax,%edx       # Set up the destination.
559         popl    %ecx    # Restore eax and ecx.
560         popl    %eax
561         ret
562         SIZE(GNAME(alloc_8_to_edx))
563
564         .globl  GNAME(alloc_16_to_edx)
565         TYPE(GNAME(alloc_16_to_edx))
566         .align  align_4byte,0x90
567 GNAME(alloc_16_to_edx):
568         pushl   %eax    # Save eax and ecx as C could destroy them.
569         pushl   %ecx
570         pushl   $16     # Push the size.
571         call    GNAME(alloc)
572         addl    $4,%esp # Pop the size arg.
573         movl    %eax,%edx       # Set up the destination.
574         popl    %ecx    # Restore eax and ecx.
575         popl    %eax
576         ret
577         SIZE(GNAME(alloc_16_to_edx))
578
579
580
581         .globl  GNAME(alloc_to_ebx)
582         TYPE(GNAME(alloc_to_ebx))
583         .align  align_4byte,0x90
584 GNAME(alloc_to_ebx):
585         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
586         pushl   %ecx
587         pushl   %edx
588         pushl   %ebx    # Push the size.
589         call    GNAME(alloc)
590         addl    $4,%esp # Pop the size arg.
591         movl    %eax,%ebx       # Set up the destination.
592         popl    %edx    # Restore eax, ecx and edx.
593         popl    %ecx
594         popl    %eax
595         ret
596         SIZE(GNAME(alloc_to_ebx))
597
598         .globl  GNAME(alloc_8_to_ebx)
599         TYPE(GNAME(alloc_8_to_ebx))
600         .align  align_4byte,0x90
601 GNAME(alloc_8_to_ebx):
602         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
603         pushl   %ecx
604         pushl   %edx
605         pushl   $8      # Push the size.
606         call    GNAME(alloc)
607         addl    $4,%esp # Pop the size arg.
608         movl    %eax,%ebx       # Set up the destination.
609         popl    %edx    # Restore eax, ecx and edx.
610         popl    %ecx
611         popl    %eax
612         ret
613         SIZE(GNAME(alloc_8_to_ebx))
614
615         .globl  GNAME(alloc_16_to_ebx)
616         TYPE(GNAME(alloc_16_to_ebx))
617         .align  align_4byte,0x90
618 GNAME(alloc_16_to_ebx):
619         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
620         pushl   %ecx
621         pushl   %edx
622         pushl   $16     # Push the size
623         call    GNAME(alloc)
624         addl    $4,%esp # pop the size arg.
625         movl    %eax,%ebx       # setup the destination.
626         popl    %edx    # Restore eax, ecx and edx.
627         popl    %ecx
628         popl    %eax
629         ret
630         SIZE(GNAME(alloc_16_to_ebx))
631
632
633
634         .globl  GNAME(alloc_to_esi)
635         TYPE(GNAME(alloc_to_esi))
636         .align  align_4byte,0x90
637 GNAME(alloc_to_esi):
638         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
639         pushl   %ecx
640         pushl   %edx
641         pushl   %esi    # Push the size
642         call    GNAME(alloc)
643         addl    $4,%esp # pop the size arg.
644         movl    %eax,%esi       # setup the destination.
645         popl    %edx    # Restore eax, ecx and edx.
646         popl    %ecx
647         popl    %eax
648         ret
649         SIZE(GNAME(alloc_to_esi))
650
651         .globl  GNAME(alloc_8_to_esi)
652         TYPE(GNAME(alloc_8_to_esi))
653         .align  align_4byte,0x90
654 GNAME(alloc_8_to_esi):
655         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
656         pushl   %ecx
657         pushl   %edx
658         pushl   $8      # Push the size
659         call    GNAME(alloc)
660         addl    $4,%esp # pop the size arg.
661         movl    %eax,%esi       # setup the destination.
662         popl    %edx    # Restore eax, ecx and edx.
663         popl    %ecx
664         popl    %eax
665         ret
666         SIZE(GNAME(alloc_8_to_esi))
667
668         .globl  GNAME(alloc_16_to_esi)
669         TYPE(GNAME(alloc_16_to_esi))
670         .align  align_4byte,0x90
671 GNAME(alloc_16_to_esi):
672         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
673         pushl   %ecx
674         pushl   %edx
675         pushl   $16     # Push the size
676         call    GNAME(alloc)
677         addl    $4,%esp # pop the size arg.
678         movl    %eax,%esi       # setup the destination.
679         popl    %edx    # Restore eax, ecx and edx.
680         popl    %ecx
681         popl    %eax
682         ret
683         SIZE(GNAME(alloc_16_to_esi))
684
685
686         .globl  GNAME(alloc_to_edi)
687         TYPE(GNAME(alloc_to_edi))
688         .align  align_4byte,0x90
689 GNAME(alloc_to_edi):
690         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
691         pushl   %ecx
692         pushl   %edx
693         pushl   %edi    # Push the size
694         call    GNAME(alloc)
695         addl    $4,%esp # pop the size arg.
696         movl    %eax,%edi       # setup the destination.
697         popl    %edx    # Restore eax, ecx and edx.
698         popl    %ecx
699         popl    %eax
700         ret
701         SIZE(GNAME(alloc_to_edi))
702
703         .globl  GNAME(alloc_8_to_edi)
704         TYPE(GNAME(alloc_8_to_edi))
705         .align  align_4byte,0x90
706 GNAME(alloc_8_to_edi):
707         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
708         pushl   %ecx
709         pushl   %edx
710         pushl   $8      # Push the size
711         call    GNAME(alloc)
712         addl    $4,%esp # pop the size arg.
713         movl    %eax,%edi       # setup the destination.
714         popl    %edx    # Restore eax, ecx and edx.
715         popl    %ecx
716         popl    %eax
717         ret
718         SIZE(GNAME(alloc_8_to_edi))
719
720         .globl  GNAME(alloc_16_to_edi)
721         TYPE(GNAME(alloc_16_to_edi))
722         .align  align_4byte,0x90
723 GNAME(alloc_16_to_edi):
724         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
725         pushl   %ecx
726         pushl   %edx
727         pushl   $16     # Push the size
728         call    GNAME(alloc)
729         addl    $4,%esp # pop the size arg.
730         movl    %eax,%edi       # setup the destination.
731         popl    %edx    # Restore eax, ecx and edx.
732         popl    %ecx
733         popl    %eax
734         ret
735         SIZE(GNAME(alloc_16_to_edi))
736
737         
738 /* Called from lisp when an inline allocation overflows.
739    Every register except the result needs to be preserved.
740    We depend on C to preserve ebx, esi, edi, and ebp.
741    But where necessary must save eax, ecx, edx. */
742
743 #ifdef LISP_FEATURE_SB_THREAD
744 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
745 #else
746 #define START_REGION GNAME(boxed_region)
747 #endif
748                 
749 /* This routine handles an overflow with eax=crfp+size. So the
750    size=eax-crfp. */
751         .align  align_4byte
752         .globl  GNAME(alloc_overflow_eax)
753         TYPE(GNAME(alloc_overflow_eax))
754 GNAME(alloc_overflow_eax):
755         pushl   %ecx            # Save ecx
756         pushl   %edx            # Save edx
757         /* Calculate the size for the allocation. */
758         subl    START_REGION,%eax
759         pushl   %eax            # Push the size
760         call    GNAME(alloc)
761         addl    $4,%esp # pop the size arg.
762         popl    %edx    # Restore edx.
763         popl    %ecx    # Restore ecx.
764         ret
765         SIZE(GNAME(alloc_overflow_eax))
766
767         .align  align_4byte
768         .globl  GNAME(alloc_overflow_ecx)
769         TYPE(GNAME(alloc_overflow_ecx))
770 GNAME(alloc_overflow_ecx):
771         pushl   %eax            # Save eax
772         pushl   %edx            # Save edx
773         /* Calculate the size for the allocation. */
774         subl    START_REGION,%ecx
775         pushl   %ecx            # Push the size
776         call    GNAME(alloc)
777         addl    $4,%esp # pop the size arg.
778         movl    %eax,%ecx       # setup the destination.
779         popl    %edx    # Restore edx.
780         popl    %eax    # Restore eax.
781         ret
782         SIZE(GNAME(alloc_overflow_ecx))
783
784         .align  align_4byte
785         .globl  GNAME(alloc_overflow_edx)
786         TYPE(GNAME(alloc_overflow_edx))
787 GNAME(alloc_overflow_edx):
788         pushl   %eax            # Save eax
789         pushl   %ecx            # Save ecx
790         /* Calculate the size for the allocation. */
791         subl    START_REGION,%edx
792         pushl   %edx            # Push the size
793         call    GNAME(alloc)
794         addl    $4,%esp # pop the size arg.
795         movl    %eax,%edx       # setup the destination.
796         popl    %ecx    # Restore ecx.
797         popl    %eax    # Restore eax.
798         ret
799         SIZE(GNAME(alloc_overflow_edx))
800
801 /* This routine handles an overflow with ebx=crfp+size. So the
802    size=ebx-crfp. */
803         .align  align_4byte
804         .globl  GNAME(alloc_overflow_ebx)
805         TYPE(GNAME(alloc_overflow_ebx))
806 GNAME(alloc_overflow_ebx):
807         pushl   %eax            # Save eax
808         pushl   %ecx            # Save ecx
809         pushl   %edx            # Save edx
810         /* Calculate the size for the allocation. */
811         subl    START_REGION,%ebx
812         pushl   %ebx            # Push the size
813         call    GNAME(alloc)
814         addl    $4,%esp # pop the size arg.
815         movl    %eax,%ebx       # setup the destination.
816         popl    %edx    # Restore edx.
817         popl    %ecx    # Restore ecx.
818         popl    %eax    # Restore eax.
819         ret
820         SIZE(GNAME(alloc_overflow_ebx))
821
822 /* This routine handles an overflow with esi=crfp+size. So the
823    size=esi-crfp. */
824         .align  align_4byte
825         .globl  GNAME(alloc_overflow_esi)
826         TYPE(GNAME(alloc_overflow_esi))
827 GNAME(alloc_overflow_esi):
828         pushl   %eax            # Save eax
829         pushl   %ecx            # Save ecx
830         pushl   %edx            # Save edx
831         /* Calculate the size for the allocation. */
832         subl    START_REGION,%esi
833         pushl   %esi            # Push the size
834         call    GNAME(alloc)
835         addl    $4,%esp # pop the size arg.
836         movl    %eax,%esi       # setup the destination.
837         popl    %edx    # Restore edx.
838         popl    %ecx    # Restore ecx.
839         popl    %eax    # Restore eax.
840         ret
841         SIZE(GNAME(alloc_overflow_esi))
842
843         .align  align_4byte
844         .globl  GNAME(alloc_overflow_edi)
845         TYPE(GNAME(alloc_overflow_edi))
846 GNAME(alloc_overflow_edi):
847         pushl   %eax            # Save eax
848         pushl   %ecx            # Save ecx
849         pushl   %edx            # Save edx
850         /* Calculate the size for the allocation. */
851         subl    START_REGION,%edi
852         pushl   %edi            # Push the size
853         call    GNAME(alloc)
854         addl    $4,%esp # pop the size arg.
855         movl    %eax,%edi       # setup the destination.
856         popl    %edx    # Restore edx.
857         popl    %ecx    # Restore ecx.
858         popl    %eax    # Restore eax.
859         ret
860         SIZE(GNAME(alloc_overflow_edi))
861
862
863 #ifdef LISP_FEATURE_WIN32
864         /* The guts of the exception-handling system doesn't use
865          * frame pointers, which manages to throw off backtraces
866          * rather badly.  So here we grab the (known-good) EBP
867          * and EIP from the exception context and use it to fake
868          * up a stack frame which will skip over the system SEH
869          * code. */
870         .align  align_4byte
871         .globl  GNAME(exception_handler_wrapper)
872         TYPE(GNAME(exception_handler_wrapper))
873 GNAME(exception_handler_wrapper):
874         /* Context layout is: */
875         /* 7 dwords before FSA. (0x1c) */
876         /* 8 dwords and 0x50 bytes in the FSA. (0x70/0x8c) */
877         /* 4 dwords segregs. (0x10/0x9c) */
878         /* 6 dwords non-stack GPRs. (0x18/0xb4) */
879         /* EBP (at 0xb4) */
880         /* EIP (at 0xb8) */
881 #define CONTEXT_EBP_OFFSET 0xb4
882 #define CONTEXT_EIP_OFFSET 0xb8
883         /* some other stuff we don't care about. */
884         pushl   %ebp
885         movl    0x10(%esp), %ebp        /* context */
886         pushl   CONTEXT_EIP_OFFSET(%ebp)
887         pushl   CONTEXT_EBP_OFFSET(%ebp)
888         movl    %esp, %ebp
889         pushl   0x1c(%esp)
890         pushl   0x1c(%esp)
891         pushl   0x1c(%esp)
892         pushl   0x1c(%esp)
893         call    GNAME(handle_exception)
894         lea     8(%ebp), %esp
895         popl    %ebp
896         ret
897         SIZE(GNAME(exception_handler_wrapper))
898 #endif
899
900 #ifdef LISP_FEATURE_DARWIN
901         .align align_4byte
902         .globl GNAME(call_into_lisp_tramp)
903         TYPE(GNAME(call_into_lisp_tramp))
904 GNAME(call_into_lisp_tramp):
905         /* 1. build the stack frame from the block that's pointed to by ECX
906            2. free the block
907            3. set ECX to 0
908            4. call the function via call_into_lisp
909         */
910         pushl   0(%ecx)          /* return address */
911
912         pushl   %ebp
913         movl    %esp, %ebp
914
915         pushl   32(%ecx)         /* eflags */
916         pushl   28(%ecx)         /* EAX */
917         pushl   20(%ecx)         /* ECX */
918         pushl   16(%ecx)         /* EDX */
919         pushl   24(%ecx)         /* EBX */
920         pushl   $0                /* popal is going to ignore esp */
921         pushl   %ebp              /* is this right?? */
922         pushl   12(%ecx)         /* ESI */
923         pushl   8(%ecx)          /* EDI */
924         pushl   $0                /* args for call_into_lisp */
925         pushl   $0
926         pushl   4(%ecx)          /* function to call */
927
928         /* free our save block */
929         pushl   %ecx              /* reserve sufficient space on stack for args */
930         pushl   %ecx
931         andl    $0xfffffff0, %esp  /* align stack */
932         movl    $0x40, 4(%esp)
933         movl    %ecx, (%esp)
934         call    GNAME(os_invalidate)
935
936         /* call call_into_lisp */
937         leal    -48(%ebp), %esp
938         call    GNAME(call_into_lisp)
939
940         /* Clean up our mess */
941         leal    -36(%ebp), %esp
942         popal
943         popfl
944         leave
945         ret
946         
947         SIZE(call_into_lisp_tramp)
948 #endif
949         
950         .align  align_4byte,0x90
951         .globl  GNAME(post_signal_tramp)
952         TYPE(GNAME(post_signal_tramp))
953 GNAME(post_signal_tramp):
954         /* this is notionally the second half of a function whose first half
955          * doesn't exist.  This is where call_into_lisp returns when called 
956          * using return_to_lisp_function */
957         addl $12,%esp   /* clear call_into_lisp args from stack */
958         popal           /* restore registers */
959         popfl
960 #ifdef LISP_FEATURE_DARWIN
961         /* skip two padding words */
962         addl $8,%esp
963 #endif
964         leave
965         ret
966         SIZE(GNAME(post_signal_tramp))
967
968
969         /* fast_bzero implementations and code to detect which implementation
970          * to use.
971          */
972 \f
973         .globl GNAME(fast_bzero_pointer)
974         .data
975         .align  align_4byte
976 GNAME(fast_bzero_pointer):
977         /* Variable containing a pointer to the bzero function to use.
978          * Initially points to a basic function.  Change this variable
979          * to fast_bzero_detect if OS supports SSE.  */
980         .long GNAME(fast_bzero_base)
981 \f
982         .text
983         .align  align_8byte,0x90
984         .globl GNAME(fast_bzero)
985         TYPE(GNAME(fast_bzero))
986 GNAME(fast_bzero):        
987         /* Indirect function call */
988         jmp *GNAME(fast_bzero_pointer)
989         SIZE(GNAME(fast_bzero))
990         
991 \f      
992         .text
993         .align  align_8byte,0x90
994         .globl GNAME(fast_bzero_detect)
995         TYPE(GNAME(fast_bzero_detect))
996 GNAME(fast_bzero_detect):
997         /* Decide whether to use SSE, MMX or REP version */
998         push %eax /* CPUID uses EAX-EDX */
999         push %ebx
1000         push %ecx
1001         push %edx
1002         mov $1, %eax
1003         cpuid
1004         test $0x04000000, %edx    /* SSE2 needed for MOVNTDQ */
1005         jnz Lsse2
1006         /* Originally there was another case here for using the
1007          * MOVNTQ instruction for processors that supported MMX but
1008          * not SSE2. This turned out to be a loss especially on
1009          * Athlons (where this instruction is apparently microcoded
1010          * somewhat slowly). So for simplicity revert to REP STOSL
1011          * for all non-SSE2 processors.
1012          */
1013 Lbase:
1014         movl $(GNAME(fast_bzero_base)), GNAME(fast_bzero_pointer)
1015         jmp Lrestore
1016 Lsse2:
1017         movl $(GNAME(fast_bzero_sse)), GNAME(fast_bzero_pointer)
1018         jmp Lrestore
1019         
1020 Lrestore:
1021         pop %edx
1022         pop %ecx
1023         pop %ebx
1024         pop %eax
1025         jmp *GNAME(fast_bzero_pointer)
1026         
1027         SIZE(GNAME(fast_bzero_detect))
1028         
1029 \f
1030         .text
1031         .align  align_8byte,0x90
1032         .globl GNAME(fast_bzero_sse)
1033         TYPE(GNAME(fast_bzero_sse))
1034         
1035 GNAME(fast_bzero_sse):
1036         /* A fast routine for zero-filling blocks of memory that are
1037          * guaranteed to start and end at a 4096-byte aligned address.
1038          */        
1039         push %esi                 /* Save temporary registers */
1040         push %edi
1041         mov 16(%esp), %esi        /* Parameter: amount of bytes to fill */
1042         mov 12(%esp), %edi        /* Parameter: start address */
1043         shr $6, %esi              /* Amount of 64-byte blocks to copy */
1044         jz Lend_sse               /* If none, stop */
1045         movups %xmm7, -16(%esp)   /* Save XMM register */
1046         xorps  %xmm7, %xmm7       /* Zero the XMM register */
1047         jmp Lloop_sse
1048         .align align_16byte
1049 Lloop_sse:
1050
1051         /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the
1052          * non-caching double-quadword moving variant, i.e. the memory areas
1053          * we're touching are not fetched into the L1 cache, since we're just
1054          * going to overwrite the memory soon anyway.
1055          */
1056         movntdq %xmm7, 0(%edi)
1057         movntdq %xmm7, 16(%edi)
1058         movntdq %xmm7, 32(%edi)
1059         movntdq %xmm7, 48(%edi)
1060  
1061         add $64, %edi /* Advance pointer */
1062         dec %esi      /* Decrement 64-byte block count */
1063         jnz Lloop_sse
1064         movups -16(%esp), %xmm7 /* Restore the XMM register */
1065         sfence        /* Ensure that weakly ordered writes are flushed. */
1066 Lend_sse:
1067         mov 12(%esp), %esi      /* Parameter: start address */
1068         prefetcht0 0(%esi)      /* Prefetch the start of the block into cache,
1069                                  * since it's likely to be used immediately. */
1070         pop %edi      /* Restore temp registers */
1071         pop %esi
1072         ret
1073         SIZE(GNAME(fast_bzero_sse))
1074                 
1075 \f
1076         .text
1077         .align  align_8byte,0x90
1078         .globl GNAME(fast_bzero_base)
1079         TYPE(GNAME(fast_bzero_base))
1080         
1081 GNAME(fast_bzero_base):
1082         /* A fast routine for zero-filling blocks of memory that are
1083          * guaranteed to start and end at a 4096-byte aligned address.
1084          */        
1085         push %eax                 /* Save temporary registers */
1086         push %ecx
1087         push %edi
1088         mov 20(%esp), %ecx        /* Parameter: amount of bytes to fill */
1089         mov 16(%esp), %edi        /* Parameter: start address */
1090         xor %eax, %eax            /* Zero EAX */
1091         shr $2, %ecx              /* Amount of 4-byte blocks to copy */
1092         jz  Lend_base
1093         cld                       /* Set direction of STOSL to increment */
1094
1095         rep
1096         stosl                     /* Store EAX to *EDI, ECX times, incrementing
1097                                    * EDI by 4 after each store */
1098         
1099 Lend_base:        
1100         pop %edi                  /* Restore temp registers */
1101         pop %ecx
1102         pop %eax
1103         ret
1104         SIZE(GNAME(fast_bzero_base))
1105         
1106 \f       
1107         END()
1108