Skip to content

Commit 893a9c4

Browse files
committed
Async exns
1 parent f393310 commit 893a9c4

39 files changed

+593
-106
lines changed

backend/cfg/cfg.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ let can_raise_operation : operation -> bool = function
386386
387387
let can_raise_basic : basic -> bool = function
388388
| Op op -> can_raise_operation op
389-
| Call _ -> true
389+
| Call (P (Alloc _)) -> false
390+
| Call (P (External _ | Checkbound _)) | Call (F _) -> true
390391
| Reloadretaddr -> false
391392
| Pushtrap _ -> false
392393
| Poptrap -> false

backend/mach.ml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ let operation_can_raise op =
204204
match op with
205205
| Icall_ind | Icall_imm _ | Iextcall _
206206
| Iintop (Icheckbound) | Iintop_imm (Icheckbound, _)
207-
| Iprobe _
208-
| Ialloc _ -> true
207+
| Iprobe _ -> true
209208
| Ispecific sop -> Arch.operation_can_raise sop
210209
| Iintop_imm((Iadd | Isub | Imul | Imulh _ | Idiv | Imod | Iand | Ior | Ixor
211210
| Ilsl | Ilsr | Iasr | Ipopcnt | Iclz _|Ictz _|Icomp _), _)
@@ -217,7 +216,7 @@ let operation_can_raise op =
217216
| Istackoffset _ | Istore _ | Iload (_, _, _) | Iname_for_debugger _
218217
| Itailcall_imm _ | Itailcall_ind
219218
| Iopaque | Ibeginregion | Iendregion
220-
| Iprobe_is_enabled _
219+
| Iprobe_is_enabled _ | Ialloc _
221220
-> false
222221

223222
let free_conts_for_handlers fundecl =

ocaml/otherlibs/systhreads/st_stubs.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ struct caml_thread_struct {
7878
uintnat last_retaddr; /* Saved value of Caml_state->last_return_address */
7979
value * gc_regs; /* Saved value of Caml_state->gc_regs */
8080
char * exception_pointer; /* Saved value of Caml_state->exception_pointer */
81+
char * async_exception_pointer;
82+
/* Saved value of Caml_state->async_exception_pointer */
8183
struct caml__roots_block * local_roots; /* Saved value of local_roots */
8284
struct caml_local_arenas * local_arenas;
8385
struct longjmp_buffer * exit_buf; /* For thread exit */
@@ -90,6 +92,8 @@ struct caml_thread_struct {
9092
/* Saved value of Caml_state->local_roots */
9193
struct caml__roots_block * local_roots;
9294
struct longjmp_buffer * external_raise; /* Saved Caml_state->external_raise */
95+
struct longjmp_buffer * external_raise_async;
96+
/* Saved Caml_state->external_raise_async */
9397
#endif
9498
int backtrace_pos; /* Saved Caml_state->backtrace_pos */
9599
backtrace_slot * backtrace_buffer; /* Saved Caml_state->backtrace_buffer */
@@ -182,6 +186,7 @@ Caml_inline void caml_thread_save_runtime_state(void)
182186
curr_thread->last_retaddr = Caml_state->last_return_address;
183187
curr_thread->gc_regs = Caml_state->gc_regs;
184188
curr_thread->exception_pointer = Caml_state->exception_pointer;
189+
curr_thread->async_exception_pointer = Caml_state->async_exception_pointer;
185190
curr_thread->local_arenas = caml_get_local_arenas();
186191
#else
187192
curr_thread->stack_low = Caml_state->stack_low;
@@ -190,6 +195,7 @@ Caml_inline void caml_thread_save_runtime_state(void)
190195
curr_thread->sp = Caml_state->extern_sp;
191196
curr_thread->trapsp = Caml_state->trapsp;
192197
curr_thread->external_raise = Caml_state->external_raise;
198+
curr_thread->external_raise_async = Caml_state->external_raise_async;
193199
#endif
194200
curr_thread->local_roots = Caml_state->local_roots;
195201
curr_thread->backtrace_pos = Caml_state->backtrace_pos;
@@ -206,6 +212,7 @@ Caml_inline void caml_thread_restore_runtime_state(void)
206212
Caml_state->last_return_address = curr_thread->last_retaddr;
207213
Caml_state->gc_regs = curr_thread->gc_regs;
208214
Caml_state->exception_pointer = curr_thread->exception_pointer;
215+
Caml_state->async_exception_pointer = curr_thread->async_exception_pointer;
209216
caml_set_local_arenas(curr_thread->local_arenas);
210217
#else
211218
Caml_state->stack_low = curr_thread->stack_low;
@@ -214,6 +221,7 @@ Caml_inline void caml_thread_restore_runtime_state(void)
214221
Caml_state->extern_sp = curr_thread->sp;
215222
Caml_state->trapsp = curr_thread->trapsp;
216223
Caml_state->external_raise = curr_thread->external_raise;
224+
Caml_state->external_raise_async = curr_thread->external_raise_async;
217225
#endif
218226
Caml_state->local_roots = curr_thread->local_roots;
219227
Caml_state->backtrace_pos = curr_thread->backtrace_pos;
@@ -334,6 +342,7 @@ static caml_thread_t caml_thread_new_info(void)
334342
th->top_of_stack = NULL;
335343
th->last_retaddr = 1;
336344
th->exception_pointer = NULL;
345+
th->async_exception_pointer = NULL;
337346
th->local_roots = NULL;
338347
th->local_arenas = NULL;
339348
th->exit_buf = NULL;
@@ -346,6 +355,7 @@ static caml_thread_t caml_thread_new_info(void)
346355
th->trapsp = th->stack_high;
347356
th->local_roots = NULL;
348357
th->external_raise = NULL;
358+
th->external_raise_async = NULL;
349359
#endif
350360
th->backtrace_pos = 0;
351361
th->backtrace_buffer = NULL;
@@ -720,12 +730,12 @@ CAMLprim value caml_thread_yield(value unit) /* ML */
720730
our blocking section doesn't contain anything interesting, don't bother
721731
with saving errno.)
722732
*/
723-
caml_raise_if_exception(caml_process_pending_signals_exn());
733+
caml_raise_async_if_exception(caml_process_pending_signals_exn());
724734
caml_thread_save_runtime_state();
725735
st_thread_yield(&caml_master_lock);
726736
curr_thread = st_tls_get(thread_descriptor_key);
727737
caml_thread_restore_runtime_state();
728-
caml_raise_if_exception(caml_process_pending_signals_exn());
738+
caml_raise_async_if_exception(caml_process_pending_signals_exn());
729739

730740
return Val_unit;
731741
}

ocaml/runtime/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ include $(ROOTDIR)/Makefile.common
2121

2222
BYTECODE_C_SOURCES := $(addsuffix .c, \
2323
interp misc stacks fix_code startup_aux startup_byt freelist major_gc \
24-
minor_gc memory alloc roots_byt globroots fail_byt signals \
24+
minor_gc memory alloc roots_byt globroots fail fail_byt signals \
2525
signals_byt printexc backtrace_byt backtrace compare ints eventlog \
2626
floats str array io extern intern hash sys meta parsing gc_ctrl md5 obj \
2727
lexing callback debugger weak compact finalise custom dynlink \
2828
afl $(UNIX_OR_WIN32) bigarray main memprof domain \
2929
skiplist codefrag)
3030

3131
NATIVE_C_SOURCES := $(addsuffix .c, \
32-
startup_aux startup_nat main fail_nat roots_nat signals \
32+
startup_aux startup_nat main fail fail_nat roots_nat signals \
3333
signals_nat misc freelist major_gc minor_gc memory alloc compare ints \
3434
floats str array io extern intern hash sys parsing gc_ctrl eventlog md5 obj \
3535
lexing $(UNIX_OR_WIN32) printexc callback weak compact finalise custom \

ocaml/runtime/amd64.S

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -573,10 +573,22 @@ FUNCTION(G(caml_start_program))
573573
movq C_ARG_1, %r14
574574
/* Initial entry point is G(caml_program) */
575575
LEA_VAR(caml_program, %r12)
576-
/* Common code for caml_start_program and caml_callback* */
576+
LBL(caml_start_program_async_exn):
577+
/* Register the same exception handler as below for async exceptions */
578+
pushq Caml_state(async_exception_pointer); CFI_ADJUST (8)
579+
movq %rsp, %r13
580+
subq $40, %r13
581+
movq %r13, Caml_state(async_exception_pointer)
582+
jmp LBL(107a)
583+
/* Common code for caml_start_program and caml_callback*.
584+
If you update the number of stack pushes, update the number 40
585+
above. */
577586
LBL(caml_start_program):
587+
/* Save the current async exception pointer */
588+
pushq Caml_state(async_exception_pointer); CFI_ADJUST (8)
589+
LBL(107a):
590+
/* Stack is 16-aligned at this point */
578591
/* Build a callback link */
579-
subq $8, %rsp; CFI_ADJUST (8) /* stack 16-aligned */
580592
pushq Caml_state(gc_regs); CFI_ADJUST(8)
581593
pushq Caml_state(last_return_address); CFI_ADJUST(8)
582594
pushq Caml_state(bottom_of_stack); CFI_ADJUST(8)
@@ -600,7 +612,9 @@ LBL(109):
600612
popq Caml_state(bottom_of_stack); CFI_ADJUST(-8)
601613
popq Caml_state(last_return_address); CFI_ADJUST(-8)
602614
popq Caml_state(gc_regs); CFI_ADJUST(-8)
603-
addq $8, %rsp; CFI_ADJUST (-8);
615+
/* Restore the asynchronous exception pointer (this will be a no-op
616+
if this function was not invoked via [caml_start_program_async_exn]). */
617+
popq Caml_state(async_exception_pointer); CFI_ADJUST(-8)
604618
/* Restore callee-save registers. */
605619
POP_CALLEE_SAVE_REGS
606620
/* Return to caller. */
@@ -696,7 +710,7 @@ ENDFUNCTION(G(caml_raise_exception))
696710
FUNCTION(G(caml_stack_overflow))
697711
movq C_ARG_1, %r14 /* Caml_state */
698712
LEA_VAR(caml_exn_Stack_overflow, %rax)
699-
movq Caml_state(exception_pointer), %rsp /* cut the stack */
713+
movq Caml_state(async_exception_pointer), %rsp /* cut the stack */
700714
/* Recover previous exn handler */
701715
popq Caml_state(exception_pointer)
702716
ret /* jump to handler's code */
@@ -746,6 +760,20 @@ CFI_STARTPROC
746760
CFI_ENDPROC
747761
ENDFUNCTION(G(caml_callback3_asm))
748762

763+
/* Variant of caml_callback_asm that installs an async exn trap frame. */
764+
FUNCTION(G(caml_callback_asm_async_exn))
765+
CFI_STARTPROC
766+
/* Save callee-save registers */
767+
PUSH_CALLEE_SAVE_REGS
768+
/* Initial loading of arguments */
769+
movq C_ARG_1, %r14 /* Caml_state */
770+
movq C_ARG_2, %rbx /* closure */
771+
movq 0(C_ARG_3), %rax /* argument */
772+
movq 0(%rbx), %r12 /* code pointer */
773+
jmp LBL(caml_start_program_async_exn)
774+
CFI_ENDPROC
775+
ENDFUNCTION(G(caml_callback_asm_async_exn))
776+
749777
FUNCTION(G(caml_ml_array_bound_error))
750778
CFI_STARTPROC
751779
LEA_VAR(caml_array_bound_error, %rax)

ocaml/runtime/callback.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,26 @@ static void init_callback_code(void)
5151
callback_code_inited = 1;
5252
}
5353

54-
CAMLexport value caml_callbackN_exn(value closure, int narg, value args[])
54+
static int is_async_exn(value exn)
55+
{
56+
const value *break_exn;
57+
58+
if (caml_global_data == 0) return 0;
59+
60+
if (exn == Field(caml_global_data, STACK_OVERFLOW_EXN)) return 1;
61+
62+
/* "Sys.Break" must match stdlib/sys.mlp. */
63+
break_exn = caml_named_value("Sys.Break");
64+
if (break_exn != NULL && exn == *break_exn) return 1;
65+
66+
return 0;
67+
}
68+
69+
static value caml_callbackN_exn0(value closure, int narg, value args[],
70+
int catch_async_exns)
5571
{
5672
int i;
57-
value res;
73+
value res, exn;
5874

5975
CAMLassert(narg + 4 <= 256);
6076

@@ -69,9 +85,26 @@ CAMLexport value caml_callbackN_exn(value closure, int narg, value args[])
6985
callback_code[3] = narg;
7086
res = caml_interprete(callback_code, sizeof(callback_code));
7187
if (Is_exception_result(res)) Caml_state->extern_sp += narg + 4; /* PR#3419 */
88+
89+
if (!Is_exception_result(res)) return res;
90+
91+
exn = Extract_exception(res);
92+
93+
/* When not called from [Sys.with_async_exns], any asynchronous exceptions
94+
must be reraised here, rather than being returned as the result of one
95+
of the [caml_callback*] functions. This will cause them to arrive only
96+
at any [Sys.with_async_exns] and toplevel uncaught exception handler
97+
sites. */
98+
if (!catch_async_exns && is_async_exn(exn)) caml_raise_async(exn);
99+
72100
return res;
73101
}
74102

103+
CAMLexport value caml_callbackN_exn(value closure, int narg, value args[])
104+
{
105+
return caml_callbackN_exn0(closure, narg, args, 0);
106+
}
107+
75108
CAMLexport value caml_callback_exn(value closure, value arg1)
76109
{
77110
value arg[1];
@@ -97,6 +130,14 @@ CAMLexport value caml_callback3_exn(value closure,
97130
return caml_callbackN_exn(closure, 3, arg);
98131
}
99132

133+
CAMLexport value caml_callback_async_exn(value closure, value arg1)
134+
{
135+
value arg[1];
136+
arg[0] = arg1;
137+
138+
return caml_callbackN_exn0(closure, 1, arg, 1);
139+
}
140+
100141
#else
101142

102143
/* Native-code callbacks. */
@@ -156,6 +197,14 @@ CAMLexport value caml_callbackN_exn(value closure, int narg, value args[])
156197
CAMLreturn (res);
157198
}
158199

200+
extern value (caml_callback_asm_async_exn)
201+
(caml_domain_state* state, value closure, value* args);
202+
203+
CAMLexport value caml_callback_async_exn(value closure, value arg)
204+
{
205+
return caml_callback_asm_async_exn(Caml_state, closure, &arg);
206+
}
207+
159208
#endif
160209

161210
/* Exception-propagating variants of the above */

ocaml/runtime/caml/callback.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ CAMLextern value caml_callback3_exn (value closure,
3939
value arg1, value arg2, value arg3);
4040
CAMLextern value caml_callbackN_exn (value closure, int narg, value args[]);
4141

42+
CAMLextern value caml_callback_async_exn (value closure, value arg);
43+
4244
CAMLextern const value * caml_named_value (char const * name);
4345
typedef void (*caml_named_action) (const value*, char *);
4446
CAMLextern void caml_iterate_named_values(caml_named_action f);

ocaml/runtime/caml/domain_state.tbl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ DOMAIN_STATE(value*, young_limit)
2121
DOMAIN_STATE(char*, exception_pointer)
2222
/* Exception pointer that points into the current stack */
2323

24+
DOMAIN_STATE(char*, async_exception_pointer)
25+
/* Async exception pointer that points into the current stack */
26+
2427
DOMAIN_STATE(void*, young_base)
2528
DOMAIN_STATE(value*, young_start)
2629
DOMAIN_STATE(value*, young_end)
@@ -51,6 +54,7 @@ DOMAIN_STATE(value*, extern_sp)
5154
DOMAIN_STATE(value*, trapsp)
5255
DOMAIN_STATE(value*, trap_barrier)
5356
DOMAIN_STATE(struct longjmp_buffer*, external_raise)
57+
DOMAIN_STATE(struct longjmp_buffer*, external_raise_async)
5458
DOMAIN_STATE(value, exn_bucket)
5559
/* See interp.c */
5660

ocaml/runtime/caml/fail.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,20 @@ struct longjmp_buffer {
6363
#define caml_external_raise (Caml_state_field(external_raise))
6464
#define caml_exn_bucket (Caml_state_field(exn_bucket))
6565

66+
CAMLextern value caml_prepare_for_raise(value v, int *turned_into_async_exn);
67+
CAMLextern value caml_check_async_exn0(value res, const char *msg,
68+
value stack_overflow_exn);
69+
70+
CAMLextern value caml_check_async_exn(value res, const char *msg);
71+
6672
int caml_is_special_exception(value exn);
6773

6874
CAMLextern value caml_raise_if_exception(value res);
75+
CAMLextern value caml_raise_async_if_exception(value res);
76+
77+
CAMLnoreturn_start
78+
CAMLextern void caml_raise_async(value res)
79+
CAMLnoreturn_end;
6980

7081
#endif /* CAML_INTERNALS */
7182

@@ -113,6 +124,10 @@ CAMLnoreturn_start
113124
CAMLextern void caml_raise_out_of_memory (void)
114125
CAMLnoreturn_end;
115126

127+
CAMLnoreturn_start
128+
CAMLextern void caml_raise_out_of_memory_fatal (void)
129+
CAMLnoreturn_end;
130+
116131
CAMLnoreturn_start
117132
CAMLextern void caml_raise_stack_overflow (void)
118133
CAMLnoreturn_end;

ocaml/runtime/caml/printexc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ extern "C" {
2828
CAMLextern char * caml_format_exception (value);
2929
#ifdef CAML_INTERNALS
3030
CAMLnoreturn_start void caml_fatal_uncaught_exception (value) CAMLnoreturn_end;
31+
CAMLnoreturn_start void caml_fatal_uncaught_exception_with_message
32+
(value, const char *) CAMLnoreturn_end;
3133
#endif /* CAML_INTERNALS */
3234

3335
#ifdef __cplusplus

ocaml/runtime/caml/signals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#endif
2626
#include "misc.h"
2727
#include "mlvalues.h"
28+
#include "fail.h"
2829

2930
#ifdef __cplusplus
3031
extern "C" {

ocaml/runtime/caml/stack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ extern intnat * caml_frametable[];
141141
#define caml_last_return_address (Caml_state_field(last_return_address))
142142
#define caml_gc_regs (Caml_state_field(gc_regs))
143143
#define caml_exception_pointer (Caml_state_field(exception_pointer))
144+
#define caml_async_exception_pointer (Caml_state_field(async_exception_pointer))
144145

145146
CAMLextern frame_descr * caml_next_frame_descriptor(uintnat * pc, char ** sp);
146147

ocaml/runtime/debugger.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,21 @@ static void putval(struct channel *chan, value val)
274274
static void safe_output_value(struct channel *chan, value val)
275275
{
276276
struct longjmp_buffer raise_buf, * saved_external_raise;
277+
struct longjmp_buffer *saved_external_raise_async;
277278

278279
/* Catch exceptions raised by [caml_output_val] */
279280
saved_external_raise = Caml_state->external_raise;
281+
saved_external_raise_async = Caml_state->external_raise_async;
280282
if (sigsetjmp(raise_buf.buf, 0) == 0) {
281283
Caml_state->external_raise = &raise_buf;
284+
Caml_state->external_raise_async = &raise_buf;
282285
caml_output_val(chan, val, marshal_flags);
283286
} else {
284287
/* Send wrong magic number, will cause [caml_input_value] to fail */
285288
caml_really_putblock(chan, "\000\000\000\000", 4);
286289
}
287290
Caml_state->external_raise = saved_external_raise;
291+
Caml_state->external_raise_async = saved_external_raise_async;
288292
}
289293

290294
static void save_instruction(code_t pc)

ocaml/runtime/domain.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void caml_init_domain ()
5454
Caml_state->trapsp = NULL;
5555
Caml_state->trap_barrier = NULL;
5656
Caml_state->external_raise = NULL;
57+
Caml_state->external_raise_async = NULL;
5758
Caml_state->exn_bucket = Val_unit;
5859

5960
Caml_state->local_arenas = NULL;

0 commit comments

Comments
 (0)