Skip to content

Commit 758fc7d

Browse files
sadiqjdamiendoligezxavierleroymshinwell
authored
Safepoints (#10039)
This PR introduces polling instructions (Ipoll Mach instructions) to guarantee that the mutator can always be interrupted (by signals or other asynchronous actions) in a finite amount of time. Co-authored-by: Damien Doligez <damien.doligez@gmail.com> Co-authored-by: Xavier Leroy <xavierleroy@users.noreply.github.com> Co-authored-by: Mark Shinwell <mshinwell@gmail.com>
1 parent 6a42e42 commit 758fc7d

48 files changed

Lines changed: 953 additions & 63 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.depend

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,7 @@ asmcomp/asmgen.cmo : \
21972197
asmcomp/printlinear.cmi \
21982198
asmcomp/printcmm.cmi \
21992199
typing/primitive.cmi \
2200+
asmcomp/polling.cmi \
22002201
utils/misc.cmi \
22012202
asmcomp/mach.cmi \
22022203
parsing/location.cmi \
@@ -2239,6 +2240,7 @@ asmcomp/asmgen.cmx : \
22392240
asmcomp/printlinear.cmx \
22402241
asmcomp/printcmm.cmx \
22412242
typing/primitive.cmx \
2243+
asmcomp/polling.cmx \
22422244
utils/misc.cmx \
22432245
asmcomp/mach.cmx \
22442246
parsing/location.cmx \
@@ -2410,10 +2412,12 @@ asmcomp/branch_relaxation.cmi : \
24102412
asmcomp/branch_relaxation_intf.cmo : \
24112413
asmcomp/linear.cmi \
24122414
lambda/debuginfo.cmi \
2415+
asmcomp/cmm.cmi \
24132416
asmcomp/arch.cmo
24142417
asmcomp/branch_relaxation_intf.cmx : \
24152418
asmcomp/linear.cmx \
24162419
lambda/debuginfo.cmx \
2420+
asmcomp/cmm.cmx \
24172421
asmcomp/arch.cmx
24182422
asmcomp/cmm.cmo : \
24192423
utils/targetint.cmi \
@@ -2807,6 +2811,23 @@ asmcomp/mach.cmi : \
28072811
asmcomp/cmm.cmi \
28082812
parsing/asttypes.cmi \
28092813
asmcomp/arch.cmo
2814+
asmcomp/polling.cmo : \
2815+
utils/numbers.cmi \
2816+
utils/misc.cmi \
2817+
asmcomp/mach.cmi \
2818+
asmcomp/dataflow.cmi \
2819+
asmcomp/cmm.cmi \
2820+
asmcomp/polling.cmi
2821+
asmcomp/polling.cmx : \
2822+
utils/numbers.cmx \
2823+
utils/misc.cmx \
2824+
asmcomp/mach.cmx \
2825+
asmcomp/dataflow.cmx \
2826+
asmcomp/cmm.cmx \
2827+
asmcomp/polling.cmi
2828+
asmcomp/polling.cmi : \
2829+
utils/misc.cmi \
2830+
asmcomp/mach.cmi
28102831
asmcomp/printcmm.cmo : \
28112832
utils/targetint.cmi \
28122833
lambda/lambda.cmi \
@@ -2969,6 +2990,7 @@ asmcomp/scheduling.cmi : \
29692990
asmcomp/selectgen.cmo : \
29702991
asmcomp/reg.cmi \
29712992
asmcomp/proc.cmi \
2993+
asmcomp/polling.cmi \
29722994
utils/numbers.cmi \
29732995
utils/misc.cmi \
29742996
asmcomp/mach.cmi \
@@ -2982,6 +3004,7 @@ asmcomp/selectgen.cmo : \
29823004
asmcomp/selectgen.cmx : \
29833005
asmcomp/reg.cmx \
29843006
asmcomp/proc.cmx \
3007+
asmcomp/polling.cmx \
29853008
utils/numbers.cmx \
29863009
utils/misc.cmx \
29873010
asmcomp/mach.cmx \
@@ -2994,6 +3017,7 @@ asmcomp/selectgen.cmx : \
29943017
asmcomp/selectgen.cmi
29953018
asmcomp/selectgen.cmi : \
29963019
asmcomp/reg.cmi \
3020+
utils/misc.cmi \
29973021
asmcomp/mach.cmi \
29983022
lambda/debuginfo.cmi \
29993023
asmcomp/cmm.cmi \
@@ -3017,6 +3041,7 @@ asmcomp/selection.cmx : \
30173041
asmcomp/arch.cmx \
30183042
asmcomp/selection.cmi
30193043
asmcomp/selection.cmi : \
3044+
utils/misc.cmi \
30203045
asmcomp/mach.cmi \
30213046
asmcomp/cmm.cmi
30223047
asmcomp/spill.cmo : \

Changes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ OCaml 4.13.0
8585

8686
### Language features:
8787

88+
- #10039: Safepoints
89+
Add poll points to native generated code. These are effectively
90+
zero-sized allocations and fix some signal and remembered set
91+
issues. Also multicore prerequisite.
92+
(Sadiq Jaffer, Damien Doligez, Mark Shinwell, Anmol Sahoo, Stephen Dolan,
93+
Xavier Leroy reviewed by ??)
94+
8895
- #9331: Improve error messages for functor application and functor types.
8996
(Florian Angeletti and Gabriel Radanne, review by Leo White)
9097

asmcomp/CSEgen.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ method class_of_operation op =
228228
| Istackoffset _ -> Op_other
229229
| Iload(_,_,mut) -> Op_load mut
230230
| Istore(_,_,asg) -> Op_store asg
231-
| Ialloc _ -> assert false (* treated specially *)
231+
| Ialloc _ | Ipoll _ -> assert false (* treated specially *)
232232
| Iintop(Icheckbound) -> Op_checkbound
233233
| Iintop _ -> Op_pure
234234
| Iintop_imm(Icheckbound, _) -> Op_checkbound
@@ -280,14 +280,14 @@ method private cse n i =
280280
| Iop Iopaque ->
281281
(* Assume arbitrary side effects from Iopaque *)
282282
{i with next = self#cse empty_numbering i.next}
283-
| Iop (Ialloc _) ->
283+
| Iop (Ialloc _) | Iop (Ipoll _) ->
284284
(* For allocations, we must avoid extending the live range of a
285285
pseudoregister across the allocation if this pseudoreg
286286
is a derived heap pointer (a pointer into the heap that does
287287
not point to the beginning of a Caml block). PR#6484 is an
288288
example of this situation. Such pseudoregs have type [Addr].
289289
Pseudoregs with types other than [Addr] can be kept.
290-
Moreover, allocation can trigger the asynchronous execution
290+
Moreover, allocations and polls can trigger the asynchronous execution
291291
of arbitrary Caml code (finalizer, signal handler, context
292292
switch), which can contain non-initializing stores.
293293
Hence, all equations over mutable loads must be removed. *)

asmcomp/amd64/emit.mlp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,27 @@ let emit_instr env fallthrough i =
616616
def_label label;
617617
I.lea (mem64 NONE 8 R15) (res i 0)
618618
end
619+
| Lop(Ipoll { return_label }) ->
620+
I.cmp (domain_field Domainstate.Domain_young_limit) r15;
621+
let gc_call_label = new_label () in
622+
let lbl_after_poll = match return_label with
623+
| None -> new_label()
624+
| Some(lbl) -> lbl in
625+
let lbl_frame =
626+
record_frame_label env i.live (Dbg_alloc [])
627+
in
628+
begin match return_label with
629+
| None -> I.jbe (label gc_call_label)
630+
| Some return_label -> I.ja (label return_label)
631+
end;
632+
env.call_gc_sites <-
633+
{ gc_lbl = gc_call_label;
634+
gc_return_lbl = lbl_after_poll;
635+
gc_frame_lbl = lbl_frame; } :: env.call_gc_sites;
636+
begin match return_label with
637+
| None -> def_label lbl_after_poll
638+
| Some _ -> I.jmp (label gc_call_label)
639+
end
619640
| Lop(Iintop(Icomp cmp)) ->
620641
I.cmp (arg i 1) (arg i 0);
621642
I.set (cond cmp) al;
@@ -765,7 +786,8 @@ let emit_instr env fallthrough i =
765786

766787
begin match system with
767788
| S_mingw64 | S_cygwin -> D.section [".rdata"] (Some "dr") []
768-
| S_macosx | S_win64 -> () (* with LLVM/OS X and MASM, use the text segment *)
789+
| S_macosx | S_win64 -> ()
790+
(* with LLVM/OS X and MASM, use the text segment *)
769791
| _ -> D.section [".rodata"] None []
770792
end;
771793
D.align 4;

asmcomp/amd64/proc.ml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ let win64 = Arch.win64
7171
3. C callee-saved registers.
7272
This translates to the set { r10, r11 }. These registers hence cannot
7373
be used for OCaml parameter passing and must also be marked as
74-
destroyed across [Ialloc] (otherwise a call to caml_call_gc@PLT might
75-
clobber these two registers before the assembly stub saves them into
76-
the GC regs block).
74+
destroyed across [Ialloc] and [Ipoll] (otherwise a call to
75+
caml_call_gc@PLT might clobber these two registers before the assembly
76+
stub saves them into the GC regs block).
7777
*)
7878

7979
let max_arguments_for_tailcalls = 10
@@ -294,7 +294,7 @@ let destroyed_at_c_call =
294294
100;101;102;103;104;105;106;107;
295295
108;109;110;111;112;113;114;115])
296296

297-
let destroyed_at_alloc =
297+
let destroyed_at_alloc_or_poll =
298298
if X86_proc.use_plt then
299299
destroyed_by_plt_stub
300300
else
@@ -307,7 +307,7 @@ let destroyed_at_oper = function
307307
| Iop(Iintop(Idiv | Imod)) | Iop(Iintop_imm((Idiv | Imod), _))
308308
-> [| rax; rdx |]
309309
| Iop(Istore(Single, _, _)) -> [| rxmm15 |]
310-
| Iop(Ialloc _) -> destroyed_at_alloc
310+
| Iop(Ialloc _ | Ipoll _) -> destroyed_at_alloc_or_poll
311311
| Iop(Iintop(Imulh | Icomp _) | Iintop_imm((Icomp _), _))
312312
-> [| rax |]
313313
| Iswitch(_, _) -> [| rax; rdx |]
@@ -339,7 +339,7 @@ let max_register_pressure = function
339339
if fp then [| 3; 0 |] else [| 4; 0 |]
340340
| Iintop(Idiv | Imod) | Iintop_imm((Idiv | Imod), _) ->
341341
if fp then [| 10; 16 |] else [| 11; 16 |]
342-
| Ialloc _ ->
342+
| Ialloc _ | Ipoll _ ->
343343
if fp then [| 11 - num_destroyed_by_plt_stub; 16 |]
344344
else [| 12 - num_destroyed_by_plt_stub; 16 |]
345345
| Iintop(Icomp _) | Iintop_imm((Icomp _), _) ->

asmcomp/amd64/selection.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,5 @@ method! insert_op_debug env op dbg rs rd =
282282

283283
end
284284

285-
let fundecl f = (new selector)#emit_fundecl f
285+
let fundecl ~future_funcnames f =
286+
(new selector)#emit_fundecl ~future_funcnames f

asmcomp/arm/emit.mlp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,11 @@ let emit_instr env i =
620620
`{emit_label lbl_frame}: add {emit_reg i.res.(0)}, alloc_ptr, #4\n`;
621621
1 + ninstr
622622
end
623+
| Lop(Ipoll { return_label }) ->
624+
begin match return_label with
625+
None -> 0
626+
| Some lbl -> ` b {emit_label lbl}\n`; 1
627+
end
623628
| Lop(Iintop(Icomp cmp)) ->
624629
` cmp {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
625630
1 + emit_set_condition cmp i.res.(0)

asmcomp/arm/selection.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,5 @@ method! insert_op_debug env op dbg rs rd =
328328

329329
end
330330

331-
let fundecl f = (new selector)#emit_fundecl f
331+
let fundecl ~future_funcnames f =
332+
(new selector)#emit_fundecl ~future_funcnames f

asmcomp/arm64/arch.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type cmm_label = int
4242
(* Do not introduce a dependency to Cmm *)
4343

4444
type specific_operation =
45+
| Ifar_poll of { return_label: cmm_label option }
4546
| Ifar_alloc of { bytes : int; dbginfo : Debuginfo.alloc_dbginfo }
4647
| Ifar_intop_checkbound
4748
| Ifar_intop_imm_checkbound of { bound : int; }
@@ -105,6 +106,8 @@ let print_addressing printreg addr ppf arg =
105106

106107
let print_specific_operation printreg op ppf arg =
107108
match op with
109+
| Ifar_poll _ ->
110+
fprintf ppf "(far) poll"
108111
| Ifar_alloc { bytes; } ->
109112
fprintf ppf "(far) alloc %i" bytes
110113
| Ifar_intop_checkbound ->

asmcomp/arm64/emit.mlp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ let num_call_gc_and_check_bound_points env =
354354
| Lend -> totals
355355
| Lop (Ialloc _) when env.f.fun_fast ->
356356
loop instr.next (call_gc + 1, check_bound)
357+
| Lop (Ipoll _) ->
358+
loop instr.next (call_gc + 1, check_bound)
357359
| Lop (Iintop Icheckbound)
358360
| Lop (Iintop_imm (Icheckbound, _))
359361
| Lop (Ispecific (Ishiftcheckbound _)) ->
@@ -366,6 +368,7 @@ let num_call_gc_and_check_bound_points env =
366368
(* The following four should never be seen, since this function is run
367369
before branch relaxation. *)
368370
| Lop (Ispecific (Ifar_alloc _))
371+
| Lop (Ispecific (Ifar_poll _))
369372
| Lop (Ispecific Ifar_intop_checkbound)
370373
| Lop (Ispecific (Ifar_intop_imm_checkbound _))
371374
| Lop (Ispecific (Ifar_shiftcheckbound _)) -> assert false
@@ -412,6 +415,7 @@ module BR = Branch_relaxation.Make (struct
412415

413416
let classify_instr = function
414417
| Lop (Ialloc _)
418+
| Lop (Ipoll _)
415419
| Lop (Iintop Icheckbound)
416420
| Lop (Iintop_imm (Icheckbound, _))
417421
| Lop (Ispecific (Ishiftcheckbound _)) -> Some Bcc
@@ -459,6 +463,8 @@ module BR = Branch_relaxation.Make (struct
459463
based + begin match size with Single -> 2 | _ -> 1 end
460464
| Lop (Ialloc _) when f.fun_fast -> 5
461465
| Lop (Ispecific (Ifar_alloc _)) when f.fun_fast -> 6
466+
| Lop (Ipoll _) -> 3
467+
| Lop (Ispecific (Ifar_poll _)) -> 4
462468
| Lop (Ialloc { bytes = num_bytes; _ })
463469
| Lop (Ispecific (Ifar_alloc { bytes = num_bytes; _ })) ->
464470
begin match num_bytes with
@@ -517,6 +523,9 @@ module BR = Branch_relaxation.Make (struct
517523
| Lambda.Raise_notrace -> 4
518524
end
519525

526+
let relax_poll ~return_label =
527+
Lop (Ispecific (Ifar_poll { return_label }))
528+
520529
let relax_allocation ~num_bytes ~dbginfo =
521530
Lop (Ispecific (Ifar_alloc { bytes = num_bytes; dbginfo }))
522531

@@ -574,6 +583,40 @@ let assembly_code_for_allocation env i ~n ~far ~dbginfo =
574583
`{emit_label lbl_frame}: add {emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, #8\n`
575584
end
576585

586+
let assembly_code_for_poll env i ~far ~return_label =
587+
let lbl_frame = record_frame_label env i.live (Dbg_alloc []) in
588+
let lbl_call_gc = new_label() in
589+
let lbl_after_poll = match return_label with
590+
| None -> new_label()
591+
| Some lbl -> lbl in
592+
let offset = Domainstate.(idx_of_field Domain_young_limit) * 8 in
593+
` ldr {emit_reg reg_tmp1}, [{emit_reg reg_domain_state_ptr}, #{emit_int offset}]\n`;
594+
` cmp {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp1}\n`;
595+
if not far then begin
596+
match return_label with
597+
| None ->
598+
` b.ls {emit_label lbl_call_gc}\n`;
599+
`{emit_label lbl_after_poll}:\n`
600+
| Some return_label ->
601+
` b.hi {emit_label return_label}\n`;
602+
` b {emit_label lbl_call_gc}\n`;
603+
end else begin
604+
match return_label with
605+
| None ->
606+
` b.hi {emit_label lbl_after_poll}\n`;
607+
` b {emit_label lbl_call_gc}\n`;
608+
`{emit_label lbl_after_poll}:\n`
609+
| Some return_label ->
610+
let lbl = new_label () in
611+
` b.ls {emit_label lbl}\n`;
612+
` b {emit_label return_label}\n`;
613+
`{emit_label lbl}: b {emit_label lbl_call_gc}\n`
614+
end;
615+
env.call_gc_sites <-
616+
{ gc_lbl = lbl_call_gc;
617+
gc_return_lbl = lbl_after_poll;
618+
gc_frame_lbl = lbl_frame; } :: env.call_gc_sites
619+
577620
(* Output .text section directive, or named .text.caml.<name> if enabled. *)
578621

579622
let emit_named_text_section func_name =
@@ -727,6 +770,10 @@ let emit_instr env i =
727770
assembly_code_for_allocation env i ~n ~far:false ~dbginfo
728771
| Lop(Ispecific (Ifar_alloc { bytes = n; dbginfo })) ->
729772
assembly_code_for_allocation env i ~n ~far:true ~dbginfo
773+
| Lop(Ipoll { return_label }) ->
774+
assembly_code_for_poll env i ~far:false ~return_label
775+
| Lop(Ispecific (Ifar_poll { return_label })) ->
776+
assembly_code_for_poll env i ~far:true ~return_label
730777
| Lop(Iintop_imm(Iadd, n)) ->
731778
emit_addimm i.res.(0) i.arg.(0) n
732779
| Lop(Iintop_imm(Isub, n)) ->

0 commit comments

Comments
 (0)