1 ! Copyright (C) 2020 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: bootstrap.image.private compiler.codegen.relocation
4 compiler.constants compiler.units cpu.arm.assembler
5 cpu.arm.assembler.opcodes generic.single.private
6 kernel kernel.private layouts locals locals.backend
7 math math.private memory namespaces sequences slots.private
8 strings.private threads.private vocabs ;
15 : shift-arg ( -- reg ) X1 ;
16 : div-arg ( -- reg ) X0 ;
17 : mod-arg ( -- reg ) X2 ;
19 ! caller-saved registers X9-X15
20 ! callee-saved registers X19-X29
21 : temp0 ( -- reg ) X9 ;
22 : temp1 ( -- reg ) X10 ;
23 : temp2 ( -- reg ) X11 ;
24 : temp3 ( -- reg ) X12 ;
28 ! : pic-tail-reg ( -- reg ) RBX ;
29 ! : return-reg ( -- reg ) RAX ;
30 ! : nv-reg ( -- reg ) RBX ;
31 ! : stack-reg ( -- reg ) RSP ;
32 ! : frame-reg ( -- reg ) RBP ;
33 ! : link-reg ( -- reg ) R11 ;
34 ! : ctx-reg ( -- reg ) R12 ;
35 ! : vm-reg ( -- reg ) R13 ;
36 : ds-reg ( -- reg ) X5 ;
37 : rs-reg ( -- reg ) X6 ;
38 ! : fixnum>slot@ ( -- ) temp0 1 SAR ;
39 ! : rex-length ( -- n ) 1 ;
41 : jit-call ( name -- ) drop ;
42 ! RAX 0 MOV f rc-absolute-cell rel-dlsym
45 :: jit-call-1arg ( arg1s name -- ) 2drop ;
49 :: jit-call-2arg ( arg1s arg2s name -- ) 3drop ;
55 ! pic-tail-reg 5 [RIP+] LEA
56 ! 0 JMP f rc-relative rel-word-pic-tail
57 ] JIT-WORD-JUMP jit-define
60 ! no-op on x86-64. in factor contexts vm-reg always contains the
64 : jit-load-context ( -- ) ;
65 ! ctx-reg vm-reg vm-context-offset [+] MOV ;
67 : jit-save-context ( -- ) ;
69 ! The reason for -8 I think is because we are anticipating a CALL
70 ! instruction. After the call instruction, the contexts frame_top
71 ! will point to the origin jump address.
73 ! ctx-reg context-callstack-top-offset [+] R11 MOV
74 ! ctx-reg context-datastack-offset [+] ds-reg MOV
75 ! ctx-reg context-retainstack-offset [+] rs-reg MOV ;
77 ! ctx-reg must already have been loaded
78 : jit-restore-context ( -- )
79 ! ds-reg ctx-reg context-datastack-offset [+] MOV
80 ! rs-reg ctx-reg context-retainstack-offset [+] MOV ;
84 ! ! ctx-reg is preserved across the call because it is non-volatile
87 ! ! call the primitive
89 ! RAX 0 MOV f f rc-absolute-cell rel-dlsym
92 ] JIT-PRIMITIVE jit-define
95 : jit-jump-quot ( -- ) ;
96 ! arg1 quot-entry-point-offset [+] JMP ;
98 : jit-call-quot ( -- ) ;
99 ! arg1 quot-entry-point-offset [+] CALL ;
101 : signal-handler-save-regs ( -- regs ) { } ;
102 ! { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 R13 R14 R15 } ;
106 ! temp2 0 MOV f rc-absolute-cell rel-literal
108 ] PIC-CHECK-TUPLE jit-define
113 1 bootstrap-cells rs-reg rs-reg ADDi64
114 -1 bootstrap-cells ds-reg rs-reg LDR-post ;
117 1 bootstrap-cells ds-reg ds-reg ADDi64
118 -1 bootstrap-cells rs-reg ds-reg LDR-post ;
121 1 bootstrap-cells rs-reg rs-reg ADDi64
122 -1 bootstrap-cells ds-reg rs-reg LDR-post
123 1 bootstrap-cells rs-reg rs-reg ADDi64
124 -1 bootstrap-cells ds-reg rs-reg LDR-post ;
127 1 bootstrap-cells ds-reg ds-reg ADDi64
128 -1 bootstrap-cells rs-reg ds-reg LDR-post
129 1 bootstrap-cells ds-reg ds-reg ADDi64
130 -1 bootstrap-cells rs-reg ds-reg LDR-post ;
133 1 bootstrap-cells rs-reg rs-reg ADDi64
134 -1 bootstrap-cells ds-reg rs-reg LDR-post
135 1 bootstrap-cells rs-reg rs-reg ADDi64
136 -1 bootstrap-cells ds-reg rs-reg LDR-post
137 1 bootstrap-cells rs-reg rs-reg ADDi64
138 -1 bootstrap-cells ds-reg rs-reg LDR-post ;
141 1 bootstrap-cells ds-reg ds-reg ADDi64
142 -1 bootstrap-cells rs-reg ds-reg LDR-post
143 1 bootstrap-cells ds-reg ds-reg ADDi64
144 -1 bootstrap-cells rs-reg ds-reg LDR-post
145 1 bootstrap-cells ds-reg ds-reg ADDi64
146 -1 bootstrap-cells rs-reg ds-reg LDR-post ;
149 : jit-switch-context ( reg -- ) drop ;
150 ! ! Push a bogus return address so the GC can track this frame back
154 ! ! Make the new context the current one
156 ! vm-reg vm-context-offset [+] ctx-reg MOV
158 ! ! Load new stack pointer
159 ! RSP ctx-reg context-callstack-top-offset [+] MOV
161 ! ! Load new ds, rs registers
162 ! jit-restore-context
164 ! ctx-reg jit-update-tib ;
166 : jit-pop-context-and-param ( -- ) ;
168 ! arg1 arg1 alien-offset [+] MOV
169 ! arg2 ds-reg -8 [+] MOV
172 : jit-push-param ( -- ) ;
174 ! ds-reg [] arg2 MOV ;
176 : jit-set-context ( -- ) ;
177 ! jit-pop-context-and-param
179 ! arg1 jit-switch-context
183 : jit-pop-quot-and-param ( -- ) ;
185 ! arg2 ds-reg -8 [+] MOV
188 : jit-start-context ( -- ) ;
189 ! Create the new context in return-reg. Have to save context
190 ! twice, first before calling new_context() which may GC,
191 ! and again after popping the two parameters from the stack.
193 ! vm-reg "new_context" jit-call-1arg
195 ! jit-pop-quot-and-param
197 ! return-reg jit-switch-context
201 : jit-delete-current-context ( -- ) ;
202 ! vm-reg "delete_context" jit-call-1arg ;
206 ! 0 CALL f rc-relative rel-word
214 ! 0 [RIP+] EAX MOV rc-relative rel-safepoint
215 ] JIT-SAFEPOINT jit-define
217 ! # All arm.64 subprimitives
221 ! { (set-context) [ jit-set-context ] }
222 ! { (set-context-and-delete) [
223 ! jit-delete-current-context
226 ! { (start-context) [ jit-start-context ] }
227 ! { (start-context-and-delete) [ jit-start-context-and-delete ] }
231 { unwind-native-frames [ ] }
234 ! { fixnum+ [ [ ADD ] "overflow_fixnum_add" jit-overflow ] }
235 ! { fixnum- [ [ SUB ] "overflow_fixnum_subtract" jit-overflow ] }
240 ! RBX ds-reg 8 [+] MOV
241 ! RBX tag-bits get SAR
248 ! arg1 tag-bits get SAR
251 ! "overflow_fixnum_multiply" jit-call
266 ! RSP [] arg1 16-bit-version-of MOV
271 ! ! Load callstack object
273 ! ds-reg bootstrap-cell SUB
274 ! ! Get ctx->callstack_bottom
276 ! arg1 ctx-reg context-callstack-bottom-offset [+] MOV
277 ! ! Get top of callstack object -- 'src' for memcpy
278 ! arg2 arg4 callstack-top-offset [+] LEA
279 ! ! Get callstack length, in bytes --- 'len' for memcpy
280 ! arg3 arg4 callstack-length-offset [+] MOV
281 ! arg3 tag-bits get SHR
282 ! ! Compute new stack pointer -- 'dst' for memcpy
284 ! ! Install new stack pointer
286 ! ! Call memcpy; arguments are now in the correct registers
287 ! ! Create register shadow area for Win64
289 ! "factor_memcpy" jit-call
290 ! ! Tear down register shadow area
292 ! ! Return with new callstack
295 } define-sub-primitives
299 ! C to Factor entry point
301 ! ! Optimizing compiler's side of callback accesses
302 ! ! arguments that are on the stack via the frame pointer.
303 ! ! On x86-32 fastcall, and x86-64, some arguments are passed
304 ! ! in registers, and so the only registers that are safe for
305 ! ! use here are frame-reg, nv-reg and vm-reg.
307 ! frame-reg stack-reg MOV
309 ! ! Save all non-volatile registers
310 ! nv-regs [ PUSH ] each
314 ! ! Load VM into vm-reg
315 ! vm-reg 0 MOV 0 rc-absolute-cell rel-vm
318 ! nv-reg vm-reg vm-context-offset [+] MOV
321 ! ! Switch over to the spare context
322 ! nv-reg vm-reg vm-spare-context-offset [+] MOV
323 ! vm-reg vm-context-offset [+] nv-reg MOV
325 ! ! Save C callstack pointer
326 ! nv-reg context-callstack-save-offset [+] stack-reg MOV
328 ! ! Load Factor stack pointers
329 ! stack-reg nv-reg context-callstack-bottom-offset [+] MOV
330 ! nv-reg jit-update-tib
333 ! rs-reg nv-reg context-retainstack-offset [+] MOV
334 ! ds-reg nv-reg context-datastack-offset [+] MOV
336 ! ! Call into Factor code
337 ! link-reg 0 MOV f rc-absolute-cell rel-word
340 ! ! Load VM into vm-reg; only needed on x86-32, but doesn't
342 ! vm-reg 0 MOV 0 rc-absolute-cell rel-vm
344 ! ! Load C callstack pointer
345 ! nv-reg vm-reg vm-context-offset [+] MOV
346 ! stack-reg nv-reg context-callstack-save-offset [+] MOV
350 ! vm-reg vm-context-offset [+] nv-reg MOV
352 ! ! Restore non-volatile registers
355 ! nv-regs <reversed> [ POP ] each
359 ! ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
360 ! ! need a parameter here.
362 ! ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
363 ! 0xffff RET f rc-absolute-2 rel-untagged
364 ] CALLBACK-STUB jit-define
368 ! temp0 0 MOV f rc-absolute-cell rel-literal
369 ! ! increment datastack pointer
370 ! ds-reg bootstrap-cell ADD
371 ! ! store literal on datastack
372 ! ds-reg [] temp0 MOV
373 ] JIT-PUSH-LITERAL jit-define
376 ! 0 CALL f rc-relative rel-word-pic
377 ] JIT-WORD-CALL jit-define
379 ! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
380 ! not to trigger generation of a stack frame, so they can
381 ! peform their own prolog/epilog preserving registers.
383 ! It is important that the total is 192/64 and that it matches the
384 ! constants in vm/cpu-x86.*.hpp
385 : jit-signal-handler-prolog ( -- ) ;
386 ! ! Return address already on stack -> 8/4 bytes.
388 ! ! Push all registers. 15 regs/120 bytes on 64bit, 7 regs/28 bytes
389 ! ! on 32bit -> 128/32 bytes.
390 ! signal-handler-save-regs [ PUSH ] each
392 ! ! Push flags -> 136/36 bytes
395 ! ! Register parameter area 32 bytes, unused on platforms other than
396 ! ! windows 64 bit, but including it doesn't hurt. Plus
397 ! ! alignment. LEA used so we don't dirty flags -> 192/64 bytes.
398 ! stack-reg stack-reg 7 bootstrap-cells neg [+] LEA
402 : jit-signal-handler-epilog ( -- ) ;
403 ! stack-reg stack-reg 7 bootstrap-cells [+] LEA
405 ! signal-handler-save-regs reverse [ POP ] each ;
409 ! temp0 ds-reg [] MOV
411 ! ds-reg bootstrap-cell SUB
412 ! ! compare boolean with f
413 ! temp0 \ f type-number CMP
414 ! ! jump to true branch if not equal
415 ! 0 JNE f rc-relative rel-word
416 ! ! jump to false branch if equal
417 ! 0 JMP f rc-relative rel-word
423 ! 0 CALL f rc-relative rel-word
429 ! 0 CALL f rc-relative rel-word
431 ] JIT-2DIP jit-define
435 ! 0 CALL f rc-relative rel-word
437 ] JIT-3DIP jit-define
441 ! temp0 ds-reg [] MOV
443 ! ds-reg bootstrap-cell SUB
445 ! [ temp0 word-entry-point-offset [+] CALL ]
446 ! [ temp0 word-entry-point-offset [+] JMP ]
447 ! \ (execute) define-combinator-primitive
450 ! temp0 ds-reg [] MOV
451 ! ds-reg bootstrap-cell SUB
452 ! temp0 word-entry-point-offset [+] JMP
453 ] JIT-EXECUTE jit-define
456 ! stack-reg stack-frame-size bootstrap-cell - SUB
457 ] JIT-PROLOG jit-define
460 ! stack-reg stack-frame-size bootstrap-cell - ADD
461 ] JIT-EPILOG jit-define
465 ] JIT-RETURN jit-define
467 ! ! ! Polymorphic inline caches
469 ! The PIC stubs are not permitted to touch pic-tail-reg.
471 ! Load a value from a stack position
473 temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
474 ] PIC-LOAD jit-define
476 [ temp1/32 tag-mask get AND ] PIC-TAG jit-define
480 temp1/32 tag-mask get AND
481 temp1/32 tuple type-number CMP
483 [ temp1 temp0 tuple-class-offset [+] MOV ]
485 ] PIC-TUPLE jit-define
488 temp1/32 0x7f CMP f rc-absolute-1 rel-untagged
489 ] PIC-CHECK-TAG jit-define
491 [ 0 JE f rc-relative rel-word ] PIC-HIT jit-define
493 ! ! ! Megamorphic caches
498 ! temp1/32 tag-mask get AND
499 ! temp1/32 tag-bits get SHL
500 ! temp1/32 tuple type-number tag-fixnum CMP
502 ! [ temp1 temp0 tuple-class-offset [+] MOV ]
505 ! temp0 0 MOV f rc-absolute-cell rel-literal
506 ! ! key = hashcode(class)
508 ! bootstrap-cell 4 = [ temp2 1 SHR ] when
509 ! ! key &= cache.length - 1
510 ! temp2 mega-cache-size get 1 - bootstrap-cell * AND
511 ! ! cache += array-start-offset
512 ! temp0 array-start-offset ADD
515 ! ! if(get(cache) == class)
519 ! ! megamorphic_cache_hits++
520 ! temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
522 ! ! goto get(cache + bootstrap-cell)
523 ! temp0 temp0 bootstrap-cell [+] MOV
524 ! temp0 word-entry-point-offset [+] JMP
525 ! ! fall-through on miss
527 ] MEGA-LOOKUP jit-define
530 : jit-compare ( insn -- ) drop ;
532 ! temp3 0 MOV t rc-absolute-cell rel-literal
534 ! temp1 \ f type-number MOV
536 ! temp0 ds-reg [] MOV
537 ! ! adjust stack pointer
538 ! ds-reg bootstrap-cell SUB
539 ! ! compare with second value
540 ! ds-reg [] temp0 CMP
542 ! [ temp1 temp3 ] dip execute( dst src -- )
544 ! ds-reg [] temp1 MOV ;
547 : jit-math ( insn -- ) drop ;
548 ! ! load second input
549 ! temp0 ds-reg [] MOV
551 ! ds-reg bootstrap-cell SUB
553 ! [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
555 : jit-fixnum-/mod ( -- ) ;
556 ! ! load second parameter
557 ! temp1 ds-reg [] MOV
558 ! ! load first parameter
559 ! div-arg ds-reg bootstrap-cell neg [+] MOV
561 ! mod-arg div-arg MOV
563 ! mod-arg bootstrap-cell-bits 1 - SAR
567 ! # Rest of arm64 subprimitives
572 ! { fixnum+fast [ \ ADD jit-math ] }
575 ! { fixnum-bitand [ \ AND jit-math ] }
580 ! ds-reg [] tag-mask get XOR
582 ! { fixnum-bitor [ \ OR jit-math ] }
583 ! { fixnum-bitxor [ \ XOR jit-math ] }
584 ! { fixnum-shift-fast [
586 ! shift-arg ds-reg [] MOV
587 ! ! untag shift count
588 ! shift-arg tag-bits get SAR
589 ! ! adjust stack pointer
590 ! ds-reg bootstrap-cell SUB
592 ! temp3 ds-reg [] MOV
595 ! ! compute positive shift value in temp2
598 ! ! compute negative shift value in temp3
600 ! temp3 tag-mask get bitnot AND
602 ! ! if shift count was negative, move temp0 to temp2
605 ! ds-reg [] temp2 MOV
610 ! temp0 ds-reg [] MOV
611 ! ds-reg bootstrap-cell SUB
613 ! temp0 tag-mask get TEST
614 ! temp0 \ f type-number MOV
615 ! temp1 1 tag-fixnum MOV
617 ! ds-reg [] temp0 MOV
619 ! { eq? [ \ CMOVE jit-compare ] }
620 ! { fixnum> [ \ CMOVG jit-compare ] }
621 ! { fixnum>= [ \ CMOVGE jit-compare ] }
622 ! { fixnum< [ \ CMOVL jit-compare ] }
623 ! { fixnum<= [ \ CMOVLE jit-compare ] }
628 ! ! adjust stack pointer
629 ! ds-reg bootstrap-cell SUB
631 ! ds-reg [] mod-arg MOV
635 ! ! adjust stack pointer
636 ! ds-reg bootstrap-cell SUB
638 ! div-arg tag-bits get SHL
640 ! ds-reg [] div-arg MOV
642 ! { fixnum/mod-fast [
645 ! div-arg tag-bits get SHL
647 ! ds-reg [] mod-arg MOV
648 ! ds-reg bootstrap-cell neg [+] div-arg MOV
653 ! ! load second input
654 ! temp0 ds-reg [] MOV
656 ! ds-reg bootstrap-cell SUB
658 ! temp1 ds-reg [] MOV
659 ! ! untag second input
660 ! temp0 tag-bits get SAR
664 ! ds-reg [] temp0 MOV
668 ! { fixnum-fast [ \ SUB jit-math ] }
673 ! temp0 ds-reg [] MOV
674 ! ! adjust stack pointer
675 ! ds-reg bootstrap-cell SUB
676 ! ! turn local number into offset
678 ! ! decrement retain stack pointer
682 ! ! load local number
683 ! temp0 ds-reg [] MOV
684 ! ! turn local number into offset
687 ! temp0 rs-reg temp0 [+] MOV
689 ! ds-reg [] temp0 MOV
691 ! { load-local [ jit->r ] }
696 ! temp0 ds-reg [] MOV
697 ! ! adjust stack pointer
698 ! ds-reg bootstrap-cell SUB
700 ! temp1 ds-reg [] MOV
701 ! ! turn slot number into offset
704 ! temp1 tag-bits get SHR
705 ! temp1 tag-bits get SHL
707 ! temp0 temp1 temp0 [+] MOV
709 ! ds-reg [] temp0 MOV
711 ! { string-nth-fast [
712 ! ! load string index from stack
713 ! temp0 ds-reg bootstrap-cell neg [+] MOV
714 ! temp0 tag-bits get SHR
715 ! ! load string from stack
716 ! temp1 ds-reg [] MOV
718 ! temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
719 ! temp0 temp0 8-bit-version-of MOVZX
720 ! temp0 tag-bits get SHL
721 ! ! store character to stack
722 ! ds-reg bootstrap-cell SUB
723 ! ds-reg [] temp0 MOV
727 ! temp0 ds-reg [] MOV
729 ! temp0/32 tag-mask get AND
731 ! temp0/32 tag-bits get SHL
733 ! ds-reg [] temp0 MOV
739 ! { drop [ ds-reg bootstrap-cell SUB ] }
740 ! { 2drop [ ds-reg 2 bootstrap-cells SUB ] }
741 ! { 3drop [ ds-reg 3 bootstrap-cells SUB ] }
742 ! { 4drop [ ds-reg 4 bootstrap-cells SUB ] }
746 ! temp0 ds-reg [] MOV
747 ! ds-reg bootstrap-cell ADD
748 ! ds-reg [] temp0 MOV
751 ! temp0 ds-reg [] MOV
752 ! temp1 ds-reg bootstrap-cell neg [+] MOV
753 ! ds-reg 2 bootstrap-cells ADD
754 ! ds-reg [] temp0 MOV
755 ! ds-reg bootstrap-cell neg [+] temp1 MOV
758 ! temp0 ds-reg [] MOV
759 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
760 ! temp3 ds-reg -2 bootstrap-cells [+] MOV
761 ! ds-reg 3 bootstrap-cells ADD
762 ! ds-reg [] temp0 MOV
763 ! ds-reg -1 bootstrap-cells [+] temp1 MOV
764 ! ds-reg -2 bootstrap-cells [+] temp3 MOV
767 ! temp0 ds-reg [] MOV
768 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
769 ! temp2 ds-reg -2 bootstrap-cells [+] MOV
770 ! temp3 ds-reg -3 bootstrap-cells [+] MOV
771 ! ds-reg 4 bootstrap-cells ADD
772 ! ds-reg [] temp0 MOV
773 ! ds-reg -1 bootstrap-cells [+] temp1 MOV
774 ! ds-reg -2 bootstrap-cells [+] temp2 MOV
775 ! ds-reg -3 bootstrap-cells [+] temp3 MOV
778 ! temp0 ds-reg [] MOV
779 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
780 ! ds-reg [] temp1 MOV
781 ! ds-reg bootstrap-cell ADD
782 ! ds-reg [] temp0 MOV
785 ! ! ### Misc shufflers
787 ! temp0 ds-reg -1 bootstrap-cells [+] MOV
788 ! ds-reg bootstrap-cell ADD
789 ! ds-reg [] temp0 MOV
792 ! temp0 ds-reg -2 bootstrap-cells [+] MOV
793 ! ds-reg bootstrap-cell ADD
794 ! ds-reg [] temp0 MOV
799 ! temp0 ds-reg [] MOV
800 ! ds-reg bootstrap-cell SUB
801 ! ds-reg [] temp0 MOV
804 ! temp0 ds-reg [] MOV
805 ! ds-reg 2 bootstrap-cells SUB
806 ! ds-reg [] temp0 MOV
811 ! temp0 ds-reg [] MOV
812 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
813 ! temp3 ds-reg -2 bootstrap-cells [+] MOV
814 ! ds-reg -2 bootstrap-cells [+] temp0 MOV
815 ! ds-reg -1 bootstrap-cells [+] temp3 MOV
816 ! ds-reg [] temp1 MOV
819 ! temp0 ds-reg [] MOV
820 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
821 ! temp3 ds-reg -2 bootstrap-cells [+] MOV
822 ! ds-reg -2 bootstrap-cells [+] temp1 MOV
823 ! ds-reg -1 bootstrap-cells [+] temp0 MOV
824 ! ds-reg [] temp3 MOV
827 ! temp0 ds-reg [] MOV
828 ! temp1 ds-reg bootstrap-cell neg [+] MOV
829 ! ds-reg bootstrap-cell neg [+] temp0 MOV
830 ! ds-reg [] temp1 MOV
833 ! temp0 ds-reg -1 bootstrap-cells [+] MOV
834 ! temp1 ds-reg -2 bootstrap-cells [+] MOV
835 ! ds-reg -2 bootstrap-cells [+] temp0 MOV
836 ! ds-reg -1 bootstrap-cells [+] temp1 MOV
839 ! ! ## Signal handling
840 ! { leaf-signal-handler [
841 ! jit-signal-handler-prolog
843 ! temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
845 ! jit-signal-handler-epilog
846 ! ! Pop the fake leaf frame along with our return address
847 ! leaf-stack-frame-size bootstrap-cell - RET
850 ! jit-signal-handler-prolog
852 ! temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
854 ! jit-signal-handler-epilog
857 } define-sub-primitives
859 [ "bootstrap.arm.64" forget-vocab ] with-compilation-unit