1 #define LANGUAGE_ASSEMBLY
7 #include "genesis/closure.h"
8 #include "genesis/funcallable-instance.h"
9 #include "genesis/fdefn.h"
10 #include "genesis/static-symbols.h"
11 #include "genesis/simple-fun.h"
12 #include "genesis/symbol.h"
13 #ifdef LISP_FEATURE_SB_THREAD
14 #include "genesis/thread.h"
16 // For LDP/STP to work right
17 #if THREAD_CONTROL_STACK_POINTER_OFFSET - THREAD_CONTROL_FRAME_POINTER_OFFSET != 8
18 #error "THREAD_CONTROL_FRAME_POINTER_OFFSET - THREAD_CONTROL_STACK_POINTER_OFFSET not sequential"
23 #define LOAD_STATIC_SYMBOL_VALUE(value,sym) \
24 mov reg_TMP,((sym)-NIL+SYMBOL_VALUE_OFFSET) ;\
25 ldr value,[reg_NULL, reg_TMP]
27 #define STORE_STATIC_SYMBOL_VALUE(value,sym) \
28 mov reg_TMP,((sym)-NIL+SYMBOL_VALUE_OFFSET) ;\
29 str value,[reg_NULL, reg_TMP]
30 #ifdef LISP_FEATURE_SB_THREAD
32 str reg_wNULL,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET]
34 str wzr,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET] ;\
35 ldr reg_wTMP,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET+4] ;\
37 brk trap_PendingInterrupt ;\
41 STORE_STATIC_SYMBOL_VALUE(reg_CFP,PSEUDO_ATOMIC_ATOMIC)
44 STORE_STATIC_SYMBOL_VALUE(reg_NULL,PSEUDO_ATOMIC_ATOMIC) ;\
45 LOAD_STATIC_SYMBOL_VALUE(reg_TMP,PSEUDO_ATOMIC_INTERRUPTED) ;\
47 brk trap_PendingInterrupt ; \
51 .global call_into_lisp
52 .type call_into_lisp, %function
54 // At this point, we have:
56 // X1 - pointer to args
57 // X2 - number of args (unboxed)
58 // There will be no more than three args, so we don't need to
59 // worry about parameters to be passed on the stack.
61 // X19-X28 are callee-saved registers.
63 stp x19,x20, [sp,#-160]!
68 stp x29,x30, [sp,#80] // save the return address in x30 aka LR
71 stp d10,d11, [sp,#112]
72 stp d12,d13, [sp,#128]
73 stp d14,d15, [sp,#144]
75 // Start by finding NIL.
76 ldr reg_NULL, .known_nil
79 lsl reg_NARGS, x2, #N_FIXNUM_TAG_BITS
81 // Move args pointer out of the way of the args to be loaded.
84 // Move the function to its passing location.
87 #ifdef LISP_FEATURE_SB_THREAD
89 bl pthread_getspecific
94 // Clear the boxed registers that don't already have something
106 // Find the lisp stack and frame pointers. We're allocating a
107 // new lisp stack frame, so load the stack pointer into CFP.
108 #ifdef LISP_FEATURE_SB_THREAD
109 ldp reg_OCFP,reg_CFP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET]
111 ldr reg_OCFP, =current_control_frame_pointer
112 ldr reg_CFP, =current_control_stack_pointer
113 ldr reg_OCFP, [reg_OCFP]
114 ldr reg_CFP, [reg_CFP]
119 #ifndef LISP_FEATURE_GENCGC
120 // Copy the current allocation pointer into the symbol.
121 ldr reg_NL3, =dynamic_space_free_pointer
122 ldr reg_NL3, [reg_NL3]
123 STORE_STATIC_SYMBOL_VALUE(reg_NL3, ALLOCATION_POINTER)
126 // Clear FFCA, so the runtime knows that we're "in lisp".
127 #ifdef LISP_FEATURE_SB_THREAD
128 str xzr,[reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET]
130 ldr reg_NL3, =foreign_function_call_active
133 // We need to set up the lisp stack pointer and the basics of
134 // our stack frame while we're still in P-A. Any sooner and
135 // our stack frame can be clobbered by a stray interrupt, any
136 // later and we can end up with a half-configured stack frame
137 // when we catch a stray interrupt.
139 // Allocate our frame and set up the Lisp stack pointer
140 add reg_CSP, reg_CFP, #16
142 // Set up the "frame link"
143 str reg_OCFP, [reg_CFP]
145 // Set up the return address
147 str reg_NL3, [reg_CFP, #8]
151 // Load our function args.
152 cbz reg_NARGS, no_args
157 ldr reg_R2, [reg_R9, #16]
159 ldr reg_R1, [reg_R9, #8]
164 // Load the closure-fun (or simple-fun-self), in case we're
165 // trying to call a closure.
166 ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
168 // And, finally, call into Lisp!
169 add reg_LR, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
173 .equ .lra, .+OTHER_POINTER_LOWTAG
174 .dword RETURN_PC_HEADER_WIDETAG
176 // Correct stack pointer for return processing.
177 csel reg_CSP, reg_OCFP, reg_CSP, eq
184 // Save the lisp stack and frame pointers.
185 #ifdef LISP_FEATURE_SB_THREAD
186 stp reg_CFP,reg_CSP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET]
187 str reg_CSP, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET]
189 ldr reg_NFP, =current_control_frame_pointer
190 str reg_CFP, [reg_NFP]
191 ldr reg_OCFP, =current_control_stack_pointer
192 str reg_CSP, [reg_OCFP]
194 // Set FFCA, so the runtime knows that we're not "in lisp".
195 ldr reg_OCFP, =foreign_function_call_active
196 str reg_OCFP, [reg_OCFP]
199 #ifndef LISP_FEATURE_GENCGC
200 // Copy the current allocation pointer out from the symbol.
201 ldr reg_OCFP, =dynamic_space_free_pointer
202 LOAD_STATIC_SYMBOL_VALUE(reg_NFP, ALLOCATION_POINTER)
203 str reg_NFP, [reg_OCFP]
208 // Restore saved registers.
210 ldp d14,d15, [sp,#144]
211 ldp d12,d13, [sp,#128]
212 ldp d10,d11, [sp,#112]
216 ldp x29,x30, [sp,#80]
217 ldp x27,x28, [sp,#64]
218 ldp x25,x26, [sp,#48]
219 ldp x23,x24, [sp,#32]
220 ldp x21,x22, [sp,#16]
221 ldp x19,x20, [sp],#160
224 .size call_into_lisp, .-call_into_lisp
229 .type call_into_c, %function
231 // At this point, we have:
232 // R8 -- C function to call.
233 // LR -- Return address within the code component.
235 // All other C arguments are already stashed on the C stack.
237 // We need to convert our return address to a GC-safe format,
238 // build a stack frame to count for the "foreign" frame,
239 // switch to C mode, move the register arguments to the
240 // correct locations, call the C function, move the result to
241 // the correct location, switch back to Lisp mode, tear down
242 // our stack frame, restore the return address, and return to
245 sub reg_NARGS, reg_LR, reg_CODE
246 add reg_NFP, reg_NARGS, #OTHER_POINTER_LOWTAG
248 // Build a Lisp stack frame. We need to stash our frame link,
249 // the code component, and our return offset. Frame link goes
250 // in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
251 // slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2. The
252 // debugger knows about this layout (see COMPUTE-CALLING-FRAME
253 // in SYS:SRC;CODE;DEBUG-INT.LISP).
254 add reg_CSP, reg_CSP, #4*8
255 stp reg_CFP, reg_NFP, [reg_CSP, #-4*8]
256 str reg_CODE, [reg_CSP, #-2*8]
260 // Save the lisp stack and frame pointers.
262 #ifdef LISP_FEATURE_SB_THREAD
263 sub reg_TMP, reg_CSP, #4*8
264 stp reg_TMP,reg_CSP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET]
265 str reg_CSP, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET]
267 ldr reg_NFP, =current_control_stack_pointer
268 str reg_CSP, [reg_NFP]
269 ldr reg_NFP, =current_control_frame_pointer
270 sub reg_TMP, reg_CSP, #4*8
271 str reg_TMP, [reg_NFP]
273 // Set FFCA, so the runtime knows that we're not "in lisp".
274 ldr reg_OCFP, =foreign_function_call_active
275 str reg_OCFP, [reg_OCFP]
278 #ifndef LISP_FEATURE_GENCGC
279 // Copy the current allocation pointer out from the symbol.
280 ldr reg_NL9, =dynamic_space_free_pointer
281 LOAD_STATIC_SYMBOL_VALUE(reg_NFP, ALLOCATION_POINTER)
282 str reg_NFP, [reg_NL9]
287 // And call the C function.
289 // R8 is important for undefined_alien_function.
292 // We're back. Our main tasks are to move the C return value
293 // to where Lisp expects it, and to re-establish the Lisp
296 // Blank the boxed registers.
307 #ifndef LISP_FEATURE_SB_THREAD
315 // Restore the Lisp stack and frame pointers, but store the
316 // control frame pointer in reg_NFP (saving a register move
318 #ifdef LISP_FEATURE_SB_THREAD
319 str xzr, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET]
321 ldp reg_NFP,reg_CSP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET]
323 // Clear FFCA, so the runtime knows that we're "in lisp".
326 #ifndef LISP_FEATURE_GENCGC
327 // Copy the current allocation pointer into the symbol.
328 ldr reg_NL9, =dynamic_space_free_pointer
329 ldr reg_NL9, [reg_NL9]
330 STORE_STATIC_SYMBOL_VALUE(reg_OCFP, ALLOCATION_POINTER)
333 ldr reg_NFP, =current_control_stack_pointer
334 ldr reg_CSP, [reg_NFP]
335 ldr reg_NFP, =current_control_frame_pointer
336 ldr reg_NFP, [reg_NFP]
340 // Restore our caller state from our stack frame.
341 ldr reg_CODE, [reg_NFP, #16]
342 ldr reg_CFP, [reg_NFP]
346 add reg_LR, reg_NARGS, reg_CODE // reg_NARGS has the offset from reg_CODE
349 .size call_into_c, .-call_into_c
352 .global undefined_tramp
353 .type undefined_tramp, %object
354 .equ undefined_tramp_header, . + FUN_POINTER_LOWTAG
355 .dword SIMPLE_FUN_HEADER_WIDETAG
356 .dword undefined_tramp_header
365 // As in ppc-assem.S, point reg_CODE to the header with a
367 adr reg_CODE, undefined_tramp_header
370 brk UNDEFINED_FUN_ERROR << 8 | trap_Error
372 .byte .error_args_end - . - 1
375 // (let ((result (make-array 10 :fill-pointer 0)))
376 // (sb-c:write-var-integer
377 // (sb-c:make-sc-offset sb-vm:descriptor-reg-sc-number sb-vm::lexenv-offset)
387 .global undefined_alien_function
388 .type undefined_alien_function, %object
389 .equ undefined_alien_function_header, . + FUN_POINTER_LOWTAG
390 .dword SIMPLE_FUN_HEADER_WIDETAG
391 .dword undefined_alien_function_header
397 undefined_alien_function:
398 adr reg_CODE, undefined_alien_function_header
400 brk UNDEFINED_ALIEN_FUN_ERROR << 8 | trap_Error
402 // Error arguments for an undefined function.
404 // Encode unsigned R8, which comes from call_into_c
411 .global closure_tramp
412 .type closure_tramp, %object
413 .dword SIMPLE_FUN_HEADER_WIDETAG
414 .dword closure_tramp - SIMPLE_FUN_CODE_OFFSET
421 ldr reg_LEXENV, [reg_LEXENV, #FDEFN_FUN_OFFSET]
422 ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
423 add reg_LR, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
427 .global funcallable_instance_tramp
428 .type funcallable_instance_tramp, %object
429 .equ funcallable_instance_tramp, .+ FUN_POINTER_LOWTAG
430 .dword SIMPLE_FUN_HEADER_WIDETAG
431 .dword funcallable_instance_tramp
437 ldr reg_LEXENV, [reg_LEXENV, #FUNCALLABLE_INSTANCE_FUNCTION_OFFSET]
438 ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
439 add reg_LR, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
442 // FIXME-ARM: The following is random garbage, to make
443 // code/debug-int compile. To get the debugger working, this
444 // needs to be implemented.
446 .global fun_end_breakpoint_guts
447 .type fun_end_breakpoint_guts, %object
448 fun_end_breakpoint_guts:
449 .global fun_end_breakpoint_trap
450 .type fun_end_breakpoint_trap, %function
451 fun_end_breakpoint_trap:
452 b fun_end_breakpoint_trap
453 .global fun_end_breakpoint_end
454 fun_end_breakpoint_end:
456 #ifdef LISP_FEATURE_GENCGC
459 .type alloc_tramp, %function
461 stp reg_NL0,reg_NL1, [sp,#-80]!
462 stp reg_NL2,reg_NL3, [sp,#16]
463 stp reg_NL4,reg_NL5, [sp,#32]
464 stp reg_NL6,reg_NL7, [sp,#48]
465 stp reg_NL8,reg_NL9, [sp,#64]
467 mov x0, reg_TMP // size
469 #ifdef LISP_FEATURE_SB_THREAD
470 str reg_CSP, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET]
472 ldr reg_TMP, =foreign_function_call_active
473 str reg_TMP, [reg_TMP]
475 // Create a new frame
476 add reg_CSP,reg_CSP, #32+96
477 stp reg_CFP,reg_NULL,[reg_CSP, #-128]
478 stp reg_CODE,reg_LR,[reg_CSP, #-112]
480 stp reg_R0,reg_R1, [reg_CSP,#-96]
481 stp reg_R2,reg_R3, [reg_CSP,#-80]
482 stp reg_R4,reg_R5, [reg_CSP,#-64]
483 stp reg_R6,reg_R7, [reg_CSP,#-48]
484 stp reg_R8,reg_R9, [reg_CSP,#-32]
485 stp x20,reg_LEXENV, [reg_CSP,#-16]
487 stp q0, q1, [sp,#-512]!
492 stp q10,q11, [sp,#160]
493 stp q12,q13, [sp,#192]
494 stp q14,q15, [sp,#224]
495 stp q16,q17, [sp,#256]
496 stp q18,q19, [sp,#288]
497 stp q20,q21, [sp,#320]
498 stp q22,q23, [sp,#352]
499 stp q24,q25, [sp,#384]
500 stp q26,q27, [sp,#416]
501 stp q28,q29, [sp,#448]
502 stp q30,q31, [sp,#480]
506 ldp q30,q31, [sp,#480]
507 ldp q28,q29, [sp,#448]
508 ldp q26,q27, [sp,#416]
509 ldp q24,q25, [sp,#384]
510 ldp q22,q23, [sp,#352]
511 ldp q20,q21, [sp,#320]
512 ldp q18,q19, [sp,#288]
513 ldp q16,q17, [sp,#256]
514 ldp q14,q15, [sp,#224]
515 ldp q12,q13, [sp,#192]
516 ldp q10,q11, [sp,#160]
521 ldp q0, q1, [sp],#512
523 ldp x20, reg_LEXENV, [reg_CSP, #-16]
524 ldp reg_R8,reg_R9, [reg_CSP,#-32]
525 ldp reg_R6,reg_R7, [reg_CSP,#-48]
526 ldp reg_R4,reg_R5, [reg_CSP,#-64]
527 ldp reg_R2,reg_R3, [reg_CSP,#-80]
528 ldp reg_R0,reg_R1, [reg_CSP,#-96]
530 ldr reg_LR,[reg_CSP,#-104]
532 sub reg_CSP, reg_CSP, #32+96 // deallocate the frame
534 // foreign_function_call_active
535 #ifdef LISP_FEATURE_SB_THREAD
536 str xzr, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET]
543 ldp reg_NL8,reg_NL9, [sp,#64]
544 ldp reg_NL6,reg_NL7, [sp,#48]
545 ldp reg_NL4,reg_NL5, [sp,#32]
546 ldp reg_NL2,reg_NL3, [sp,#16]
547 ldp reg_NL0,reg_NL1, [sp],#80
553 .type fpu_save, %function
560 stp q10,q11, [x0,#160]
561 stp q12,q13, [x0,#192]
562 stp q14,q15, [x0,#224]
563 stp q16,q17, [x0,#256]
564 stp q18,q19, [x0,#288]
565 stp q20,q21, [x0,#320]
566 stp q22,q23, [x0,#352]
567 stp q24,q25, [x0,#384]
568 stp q26,q27, [x0,#416]
569 stp q28,q29, [x0,#448]
570 stp q30,q31, [x0,#480]
575 .type fpu_restore, %function
582 ldp q10,q11, [x0,#160]
583 ldp q12,q13, [x0,#192]
584 ldp q14,q15, [x0,#224]
585 ldp q16,q17, [x0,#256]
586 ldp q18,q19, [x0,#288]
587 ldp q20,q21, [x0,#320]
588 ldp q22,q23, [x0,#352]
589 ldp q24,q25, [x0,#384]
590 ldp q26,q27, [x0,#416]
591 ldp q28,q29, [x0,#448]
592 ldp q30,q31, [x0,#480]
596 .global do_pending_interrupt
597 .type do_pending_interrupt, %function
598 do_pending_interrupt:
599 brk trap_PendingInterrupt