Skip to content

Commit 4f49fdf

Browse files
committed
Mark Obj_dup as not having effects and handle in Cfg
1 parent 6b1976e commit 4f49fdf

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

backend/cfg/cfg.ml

+9-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,15 @@ let can_raise_terminator (i : terminator) =
412412
| Raise _ | Tailcall_func _ | Call _ | Prim { op = Probe _; label_after = _ }
413413
->
414414
true
415-
| Prim { op = External { alloc; _ }; label_after = _ } -> alloc
415+
| Prim { op = External { alloc; effects; _ }; label_after = _ } ->
416+
if not alloc then false
417+
else (
418+
(* Even if going via [caml_c_call], if there are no effects, the function
419+
cannot raise an exception. (Example: [caml_obj_dup].) *)
420+
match effects with
421+
| No_effects -> false
422+
| Arbitrary_effects -> true
423+
)
416424
| Specific_can_raise { op; _ } ->
417425
assert (Arch.operation_can_raise op);
418426
true

middle_end/flambda2/to_cmm/to_cmm_primitive.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ let unary_primitive env res dbg f arg =
858858
( None,
859859
res,
860860
C.extcall ~dbg ~alloc:true ~returns:true ~is_c_builtin:false
861-
~effects:Arbitrary_effects ~coeffects:Has_coeffects ~ty_args:[]
861+
~effects:No_effects ~coeffects:Has_coeffects ~ty_args:[]
862862
"caml_obj_dup" Cmm.typ_val [arg] )
863863
| Is_int _ -> None, res, C.and_int arg (C.int ~dbg 1) dbg
864864
| Is_null -> None, res, C.eq ~dbg arg (C.nativeint ~dbg 0n)

runtime/obj.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,20 @@ CAMLprim value caml_obj_with_tag(value new_tag_v, value arg)
154154
tag_t tag_for_alloc;
155155
uintnat infix_offset = 0;
156156

157+
// This function must not raise exceptions (except asynchronous exceptions).
158+
157159
tag_t new_tag = (tag_t)Long_val(new_tag_v);
160+
#ifdef DEBUG
158161
tag_t existing_tag = Tag_val(arg);
162+
#endif
159163

160-
if ((existing_tag == Closure_tag || existing_tag == Infix_tag
164+
CAMLassert (
165+
!(
166+
(existing_tag == Closure_tag || existing_tag == Infix_tag
161167
|| new_tag == Closure_tag || new_tag == Infix_tag)
162-
&& existing_tag != new_tag) {
163-
caml_failwith("Cannot change tags of existing closures or create \
164-
new closures using [caml_obj_with_tag]");
165-
}
168+
&& existing_tag != new_tag));
169+
// Cannot change tags of existing closures or create new closures using
170+
// [caml_obj_with_tag].
166171

167172
if (new_tag == Infix_tag) {
168173
// If we received an infix block, we must return the same; but the whole
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
(* TEST *)
2+
3+
[@@@ocaml.flambda_o3]
4+
5+
let[@inline never] bar _ _ = ()
6+
7+
let[@inline never] baz () = ()
8+
9+
let foo size (x : int) arr y =
10+
let extra_arg_array = ref arr in
11+
let extra_arg_int = ref 0 in
12+
(try
13+
for i = 0 to size - 1 do
14+
if i > 20 then (
15+
let _ = Sys.opaque_identity (Obj.dup y) in
16+
baz ()
17+
)
18+
done
19+
with _exn -> ());
20+
bar !extra_arg_array !extra_arg_int

0 commit comments

Comments
 (0)