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"
14 #define STATIC_SYMBOL_VALUE(sym) [reg_NULL, #(((sym)-NIL)+SYMBOL_VALUE_OFFSET)]
17 .global call_into_lisp
18 .type call_into_lisp, %function
20 @@ At this point, we have:
22 @@ R1 - pointer to args
23 @@ R2 - number of args (unboxed)
24 @@ There will be no more than three args, so we don't need to
25 @@ worry about parameters to be passed on the stack.
27 @@ All registers other than R0-R3 and R12 are callee-saves.
28 stmfd sp!, {r4-r11, lr}
30 @@ Start by finding NIL.
31 ldr reg_NULL, .known_nil
34 mov reg_NARGS, r2, lsl #2
36 @@ Move args pointer out of the way of the args to be loaded.
39 @@ Move the function to its passing location.
42 @@ Clear the boxed registers that don't already have something
47 @@ Find the lisp stack and frame pointers. We're allocating a
48 @@ new lisp stack frame, so load the stack pointer into CFP.
49 @@ And we need the frame pointer, but OCFP is in use, so use
51 ldr reg_NFP, .frame_pointer_address
52 ldr reg_CFP, .stack_pointer_address
53 ldr reg_NFP, [reg_NFP]
54 ldr reg_CFP, [reg_CFP]
56 @@ Enter PSEUDO-ATOMIC.
57 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
59 @@ Copy the current allocation pointer into the symbol.
60 ldr reg_OCFP, =dynamic_space_free_pointer
61 ldr reg_OCFP, [reg_OCFP]
62 str reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
64 @@ Clear FFCA, so the runtime knows that we're "in lisp".
65 ldr reg_OCFP, =foreign_function_call_active
66 str reg_R2, [reg_OCFP]
68 @@ Save off the C stack pointer. Once for our return sequence,
69 @@ and once for the number stack.
71 str sp, STATIC_SYMBOL_VALUE(NUMBER_STACK_POINTER)
73 @@ We need to set up the lisp stack pointer and the basics of
74 @@ our stack frame while we're still in P-A. Any sooner and
75 @@ our stack frame can be clobbered by a stray interrupt, any
76 @@ later and we can end up with a half-configured stack frame
77 @@ when we catch a stray interrupt.
79 @@ Set up the Lisp stack pointer
82 @@ Set up the "frame link"
83 stmea reg_CSP!, {reg_NFP}
85 @@ Set up the return address
87 stmea reg_CSP!, {reg_NL3}
89 @@ Leave PSEUDO-ATOMIC and check for interrupts.
90 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
91 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
92 cmp reg_OCFP, reg_NULL
93 movlt reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
96 @@ Load our function args. Cleverness abounds!
97 rsb reg_NL3, reg_NARGS, #8
99 ldr reg_R2, [reg_R8, #8]
100 ldr reg_R1, [reg_R8, #4]
103 @@ And, finally, call into Lisp!
104 add reg_PC, reg_LEXENV, #SIMPLE_FUN_CODE_OFFSET
107 .equ .lra, .+OTHER_POINTER_LOWTAG
108 .word RETURN_PC_HEADER_WIDETAG
110 @@ Correct stack pointer for return processing.
111 moveq reg_CSP, reg_OCFP
113 @@ Enter PSEUDO-ATOMIC.
114 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
116 @@ Save the lisp stack and frame pointers.
117 ldr reg_NFP, .frame_pointer_address
118 ldr reg_OCFP, .stack_pointer_address
119 str reg_CFP, [reg_NFP]
120 str reg_CSP, [reg_OCFP]
122 @@ Set FFCA, so the runtime knows that we're not "in lisp".
123 ldr reg_OCFP, =foreign_function_call_active
126 @@ Copy the current allocation pointer out from the symbol.
127 ldr reg_OCFP, =dynamic_space_free_pointer
128 ldr reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
129 str reg_NFP, [reg_OCFP]
131 @@ Restore the C stack pointer.
132 ldr sp, [reg_CSP, #-4]
134 @@ Leave PSEUDO-ATOMIC and check for interrupts.
135 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
136 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
137 cmp reg_OCFP, reg_NULL
138 movlt reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
141 @@ Restore saved registers.
142 ldmfd sp!, {r4-r11, lr}
144 .size call_into_lisp, .-call_into_lisp
145 .frame_pointer_address: .word current_control_frame_pointer
146 .stack_pointer_address: .word current_control_stack_pointer
151 .type call_into_c, %function
153 @@ At this point, we have:
154 @@ R8 -- C function to call. This routine doesn't support
155 @@ thumb interworking, but linkage-table (when we get
156 @@ around to implementing it) will, so we don't have to.
157 @@ LR -- Return address within the code component.
158 @@ OCFP -- First C register argument.
159 @@ NARGS -- Second C register argument.
160 @@ NL2 -- Third C register argument.
161 @@ NL3 -- Fourth C register argument.
162 @@ All other C arguments are already stashed on the C stack.
164 @@ We need to convert our return address to a GC-safe format,
165 @@ build a stack frame to count for the "foreign" frame,
166 @@ switch to C mode, move the register arguments to the
167 @@ correct locations, call the C function, move the result to
168 @@ the correct location, switch back to Lisp mode, tear down
169 @@ our stack frame, restore the return address, and return to
172 @@ We have ONE unboxed scratch register: NFP. Use it as a
173 @@ temporary while we convert the (unboxed) return address to
174 @@ a (fixnum) offset within the component.
175 sub reg_NFP, reg_LR, reg_CODE
176 add reg_NFP, reg_NFP, #OTHER_POINTER_LOWTAG
178 @@ Build a Lisp stack frame. We need to stash our frame link,
179 @@ the code component, and our return offset. Frame link goes
180 @@ in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
181 @@ slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2. The
182 @@ debugger knows about this layout (see COMPUTE-CALLING-FRAME
183 @@ in SYS:SRC;CODE;DEBUG-INT.LISP). The stack is aligned, so
184 @@ we can use R0 (a boxed register) as our temporary.
187 str reg_CFP, [reg_R0]
188 str reg_NFP, [reg_R0, #4]
189 str reg_CODE, [reg_R0, #8]
191 @@ Enter PSEUDO-ATOMIC.
192 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
194 @@ Save the lisp stack and frame pointers.
195 ldr reg_NFP, .frame_pointer_address
196 str reg_R0, [reg_NFP]
197 ldr reg_NFP, .stack_pointer_address
198 str reg_CSP, [reg_NFP]
200 @@ We're done with R0, and we need to use OCFP when leaving
201 @@ pseudo-atomic, so move the first of the C register
202 @@ arguments to its final resting place now.
205 @@ Set FFCA, so the runtime knows that we're not "in lisp".
206 ldr reg_NFP, =foreign_function_call_active
209 @@ Copy the current allocation pointer out from the symbol.
210 ldr reg_OCFP, =dynamic_space_free_pointer
211 ldr reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
212 str reg_NFP, [reg_OCFP]
214 @@ Pick up the C stack pointer.
215 ldr sp, STATIC_SYMBOL_VALUE(NUMBER_STACK_POINTER)
217 @@ Leave PSEUDO-ATOMIC and check for interrupts.
218 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
219 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
220 cmp reg_OCFP, reg_NULL
221 movlt reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
224 @@ Now that we're in C mode, move the remaining register args
230 @@ And call the C function. We don't support interworking
231 @@ here because we have to be able to pass the function
232 @@ pointer in a boxed register, but the linkage-table is quite
233 @@ capable of doing a tail-call to a Thumb routine. Oh, wait,
234 @@ we don't have a linkage-table yet. Oops.
237 @@ We're back. Our main tasks are to move the C return value
238 @@ to where Lisp expects it, and to re-establish the Lisp
241 @@ Stash the return value into NARGS for Lisp.
245 ldr reg_NULL, .known_nil
247 @@ Blank the boxed registers.
255 @@ Enter PSEUDO-ATOMIC.
256 str pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
258 @@ Clear FFCA, so the runtime knows that we're "in lisp".
259 ldr reg_OCFP, =foreign_function_call_active
260 str reg_R2, [reg_OCFP]
262 @@ Copy the current allocation pointer into the symbol.
263 ldr reg_OCFP, =dynamic_space_free_pointer
264 ldr reg_OCFP, [reg_OCFP]
265 str reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
267 @@ Save off the C stack pointer.
268 str sp, STATIC_SYMBOL_VALUE(NUMBER_STACK_POINTER)
270 @@ Restore the Lisp stack and frame pointers, but store the
271 @@ control frame pointer in reg_NFP (saving a register move
273 ldr reg_NFP, .stack_pointer_address
274 ldr reg_CSP, [reg_NFP]
275 ldr reg_NFP, .frame_pointer_address
276 ldr reg_NFP, [reg_NFP]
278 @@ Leave PSEUDO-ATOMIC and check for interrupts.
279 str reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
280 ldr reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
281 cmp reg_OCFP, reg_NULL
282 movlt reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
285 @@ Restore our caller state from our stack frame.
286 ldr reg_CODE, [reg_NFP, #8]
287 ldr reg_NL2, [reg_NFP, #4]
288 ldr reg_CFP, [reg_NFP]
291 @@ Restore our return address... into the program counter.
292 sub reg_NL2, reg_NL2, #OTHER_POINTER_LOWTAG
293 add reg_PC, reg_NL2, reg_CODE
295 .size call_into_c, .-call_into_c
298 /* Trampolines, like on SPARC, use Lisp calling conventions. */
300 .global undefined_tramp
301 .type undefined_tramp, %object
302 .word SIMPLE_FUN_HEADER_WIDETAG
303 .equ undefined_tramp, .+1
304 .word undefined_tramp
312 @@ The magic (undefined) "BREAK_POINT" instruction.
315 @@ Error arguments for an undefined function.
317 .byte .error_args_end - . - 1
318 .byte UNDEFINED_FUN_ERROR
319 @@ Need to indicate reg_LEXENV here, which is R3. Encoding
320 @@ rules are to produce an "sc-offset" with the SC number in
321 @@ the low five bits and the offset (3 in our case) in the
322 @@ high $n$ bits. sc_DescriptorReg happens to be 5, but we
323 @@ should use the constant for it. So long as the overall
324 @@ value of the sc-offset is less than 254, we can use a
325 @@ single byte. Overflowing that will take having the SC
326 @@ number being 30 or 31, and as of this writing the highest
327 @@ SC number is sc_CatchBlock at 16. It would also take an
328 @@ offset of 7, not the 3 that we use for LEXENV.
329 .byte sc_DescriptorReg + (0x20 * 3)
333 .global closure_tramp
334 .type closure_tramp, %object
335 .word SIMPLE_FUN_HEADER_WIDETAG
336 .equ closure_tramp, .+1
344 ldr reg_LEXENV, [reg_LEXENV, #FDEFN_FUN_OFFSET]
345 ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
346 add reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
349 .global funcallable_instance_tramp
350 .type funcallable_instance_tramp, %object
351 .word SIMPLE_FUN_HEADER_WIDETAG
352 .equ funcallable_instance_tramp, .+1
353 .word funcallable_instance_tramp
360 ldr reg_LEXENV, [reg_LEXENV, #FUNCALLABLE_INSTANCE_FUNCTION_OFFSET]
361 ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
362 add reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
364 @@ FIXME-ARM: The following is random garbage, to make
365 @@ code/debug-int compile. To get the debugger working, this
366 @@ needs to be implemented.
368 .global fun_end_breakpoint_guts
369 .type fun_end_breakpoint_guts, %object
370 fun_end_breakpoint_guts:
371 .global fun_end_breakpoint_trap
372 .type fun_end_breakpoint_trap, %function
373 fun_end_breakpoint_trap:
374 b fun_end_breakpoint_trap
375 .global fun_end_breakpoint_end
376 fun_end_breakpoint_end: