@@ -58,6 +58,14 @@ let try_stack_at_handler = ref Continuation.Map.empty
5858let recursive_static_catches = ref Numbers.Int.Set. empty
5959let mutable_variables = ref Ident.Set. empty
6060
61+ let mark_as_recursive_static_catch cont =
62+ if Numbers.Int.Set. mem cont ! recursive_static_catches then begin
63+ Misc. fatal_errorf " Static catch with continuation %d already marked as \
64+ recursive -- is it being redefined?"
65+ cont
66+ end ;
67+ recursive_static_catches := Numbers.Int.Set. add cont ! recursive_static_catches
68+
6169let _print_stack ppf stack =
6270 Format. fprintf ppf " %a"
6371 (Format. pp_print_list ~pp_sep: (fun ppf () -> Format. fprintf ppf " ; " )
@@ -116,7 +124,7 @@ let compile_staticfail ~(continuation : Continuation.t) ~args =
116124 in
117125 mk_poptraps (I. Apply_cont (continuation, None , args))
118126
119- let switch_for_if_then_else ~cond ~ifso ~ifnot k =
127+ let switch_for_if_then_else ~cond ~ifso ~ifnot =
120128 (* CR mshinwell: We need to make sure that [cond] is {0, 1}-valued.
121129 The frontend should have been fixed on this branch for this. *)
122130 let switch : Lambda.lambda_switch =
@@ -128,7 +136,7 @@ let switch_for_if_then_else ~cond ~ifso ~ifnot k =
128136 sw_tags_to_sizes = Tag.Scannable.Map. empty;
129137 }
130138 in
131- k ( L. Lswitch (cond, switch, Loc_unknown ) )
139+ L. Lswitch (cond, switch, Loc_unknown )
132140
133141let transform_primitive (prim : L.primitive ) args loc =
134142 match prim, args with
@@ -141,8 +149,7 @@ let transform_primitive (prim : L.primitive) args loc =
141149 switch_for_if_then_else
142150 ~cond: (L. Lvar cond)
143151 ~ifso: (L. Lvar const_true)
144- ~ifnot: arg2
145- (fun lam -> lam)))))
152+ ~ifnot: arg2))))
146153 | Psequand , [arg1; arg2] ->
147154 let const_false = Ident. create_local " const_false" in
148155 let cond = Ident. create_local " cond_sequand" in
@@ -152,8 +159,7 @@ let transform_primitive (prim : L.primitive) args loc =
152159 switch_for_if_then_else
153160 ~cond: (L. Lvar cond)
154161 ~ifso: arg2
155- ~ifnot: (L. Lvar const_false)
156- (fun lam -> lam)))))
162+ ~ifnot: (L. Lvar const_false)))))
157163 | (Psequand | Psequor ), _ ->
158164 Misc. fatal_error " Psequand / Psequor must have exactly two arguments"
159165 (* Removed. Should be safe, but will no longer catch misuses.
@@ -165,8 +171,7 @@ let transform_primitive (prim : L.primitive) args loc =
165171 (switch_for_if_then_else
166172 ~cond: (L. Lprim (Pflambda_isint , [arg], loc))
167173 ~ifso: (L. Lconst (Const_base (Const_int 1 )))
168- ~ifnot: (L. Lconst (Const_base (Const_int 0 )))
169- (fun lam -> lam))
174+ ~ifnot: (L. Lconst (Const_base (Const_int 0 ))))
170175 | (Pidentity | Pbytes_to_string | Pbytes_of_string ), [arg] -> Transformed arg
171176 | Pignore , [arg] ->
172177 let ident = Ident. create_local " ignore" in
@@ -247,6 +252,66 @@ let transform_primitive (prim : L.primitive) args loc =
247252 end
248253 | _ , _ -> Primitive (prim, args, loc)
249254
255+ let rec_catch_for_while_loop cond body =
256+ let cont = L. next_raise_count () in
257+ mark_as_recursive_static_catch cont;
258+ let cond_result = Ident. create_local " while_cond_result" in
259+ let lam : L.lambda =
260+ Lstaticcatch (
261+ Lstaticraise (cont, [] ),
262+ (cont, [] ),
263+ Llet (Strict , Pgenval , cond_result, cond,
264+ Lifthenelse (Lvar cond_result,
265+ Lsequence (
266+ body,
267+ Lstaticraise (cont, [] )),
268+ Lconst (Const_base (Const_int 0 )))))
269+ in lam
270+
271+ let rec_catch_for_for_loop
272+ ident start stop (dir : Asttypes.direction_flag ) body =
273+ let cont = L. next_raise_count () in
274+ mark_as_recursive_static_catch cont;
275+ let start_ident = Ident. create_local " for_start" in
276+ let stop_ident = Ident. create_local " for_stop" in
277+ let first_test : L.lambda =
278+ match dir with
279+ | Upto ->
280+ Lprim (Pintcomp Cle ,
281+ [L. Lvar start_ident; L. Lvar stop_ident],
282+ Loc_unknown )
283+ | Downto ->
284+ Lprim (Pintcomp Cge ,
285+ [L. Lvar start_ident; L. Lvar stop_ident],
286+ Loc_unknown )
287+ in
288+ let subsequent_test : L.lambda =
289+ Lprim (Pintcomp Cne , [L. Lvar ident; L. Lvar stop_ident], Loc_unknown )
290+ in
291+ let one : L.lambda = Lconst (Const_base (Const_int 1 )) in
292+ let next_value_of_counter =
293+ match dir with
294+ | Upto -> L. Lprim (Paddint , [L. Lvar ident; one], Loc_unknown )
295+ | Downto -> L. Lprim (Psubint , [L. Lvar ident; one], Loc_unknown )
296+ in
297+ let lam : L.lambda =
298+ (* Care needs to be taken here not to cause overflow if, for an
299+ incrementing for-loop, the upper bound is [max_int]; likewise, for
300+ a decrementing for-loop, if the lower bound is [min_int]. *)
301+ Llet (Strict , Pgenval , start_ident, start,
302+ Llet (Strict , Pgenval , stop_ident, stop,
303+ Lifthenelse (first_test,
304+ Lstaticcatch (
305+ Lstaticraise (cont, [L. Lvar start_ident]),
306+ (cont, [ident, Pgenval ]),
307+ Lsequence (
308+ body,
309+ Lifthenelse (subsequent_test,
310+ Lstaticraise (cont, [next_value_of_counter]),
311+ L. lambda_unit))),
312+ L. lambda_unit)))
313+ in lam
314+
250315let rec cps_non_tail (lam : L.lambda ) (k : Ident.t -> Ilambda.t )
251316 (k_exn : Continuation.t ) : Ilambda.t =
252317 match lam with
@@ -536,13 +601,25 @@ let rec cps_non_tail (lam : L.lambda) (k : Ident.t -> Ilambda.t)
536601 };
537602 handler = k result_var;
538603 }
604+ | Lifthenelse (cond , ifso , ifnot ) ->
605+ let lam = switch_for_if_then_else ~cond ~ifso ~ifnot in
606+ cps_non_tail lam k k_exn
607+ | Lsequence (lam1 , lam2 ) ->
608+ let ident = Ident. create_local " sequence" in
609+ cps_non_tail (L. Llet (Strict , Pgenval , ident, lam1, lam2)) k k_exn
610+ | Lwhile (cond , body ) ->
611+ let loop = rec_catch_for_while_loop cond body in
612+ cps_non_tail loop k k_exn
613+ | Lfor (ident , start , stop , dir , body ) ->
614+ let loop = rec_catch_for_for_loop ident start stop dir body in
615+ cps_non_tail loop k k_exn
539616 | Lassign (being_assigned , new_value ) ->
540617 cps_non_tail_simple new_value (fun new_value ->
541618 name_then_cps_non_tail " assign"
542619 (I. Assign { being_assigned; new_value; })
543620 k k_exn)
544621 k_exn
545- | Lsequence _ | Lifthenelse _ | Lwhile _ | Lfor _ | Lifused _ | Levent _ ->
622+ | Lifused _ | Levent _ ->
546623 Misc. fatal_errorf " Term should have been eliminated by [Prepare_lambda]: %a"
547624 Printlambda. lambda lam
548625
@@ -818,7 +895,19 @@ and cps_tail (lam : L.lambda) (k : Continuation.t) (k_exn : Continuation.t)
818895 };
819896 handler;
820897 }
821- | Lsequence _ | Lifthenelse _ | Lwhile _ | Lfor _ | Lifused _ | Levent _ ->
898+ | Lifthenelse (cond , ifso , ifnot ) ->
899+ let lam = switch_for_if_then_else ~cond ~ifso ~ifnot in
900+ cps_tail lam k k_exn
901+ | Lsequence (lam1 , lam2 ) ->
902+ let ident = Ident. create_local " sequence" in
903+ cps_tail (L. Llet (Strict , Pgenval , ident, lam1, lam2)) k k_exn
904+ | Lwhile (cond , body ) ->
905+ let loop = rec_catch_for_while_loop cond body in
906+ cps_tail loop k k_exn
907+ | Lfor (ident , start , stop , dir , body ) ->
908+ let loop = rec_catch_for_for_loop ident start stop dir body in
909+ cps_tail loop k k_exn
910+ | Lifused _ | Levent _ ->
822911 Misc. fatal_errorf " Term should have been eliminated by [Prepare_lambda]: %a"
823912 Printlambda. lambda lam
824913
@@ -943,12 +1032,11 @@ and cps_switch (switch : proto_switch) ~scrutinee (k : Continuation.t)
9431032 wrappers)
9441033 k_exn
9451034
946- let lambda_to_ilambda lam ~recursive_static_catches :recursive_static_catches'
947- : Ilambda.program =
1035+ let lambda_to_ilambda lam : Ilambda.program =
9481036 static_exn_env := Numbers.Int.Map. empty;
9491037 try_stack := [] ;
9501038 try_stack_at_handler := Continuation.Map. empty;
951- recursive_static_catches := recursive_static_catches' ;
1039+ recursive_static_catches := Numbers.Int.Set. empty ;
9521040 mutable_variables := Ident.Set. empty;
9531041 let the_end = Continuation. create ~sort: Define_root_symbol () in
9541042 let the_end_exn = Continuation. create ~sort: Exn () in
0 commit comments