Skip to content

Commit 1814ede

Browse files
committed
Backport lazy from 5 to 4.
1 parent f63184d commit 1814ede

File tree

13 files changed

+284
-464
lines changed

13 files changed

+284
-464
lines changed

backend/cmm_helpers.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ let get_header ptr dbg =
826826
data race on headers. This saves performance with ThreadSanitizer
827827
instrumentation by avoiding to instrument header loads. *)
828828
Cop
829-
( (if Config.runtime5 then mk_load_immut Word_int else mk_load_mut Word_int),
829+
( mk_load_immut Word_int,
830830
[Cop (Cadda, [ptr; Cconst_int (-size_int, dbg)], dbg)],
831831
dbg )
832832

ocaml/lambda/matching.ml

Lines changed: 120 additions & 265 deletions
Large diffs are not rendered by default.

ocaml/runtime4/caml/mlvalues.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ bits 63 (64-P) (63-P) 10 9 8 7 0
135135
#define Profinfo_hd(hd) NO_PROFINFO
136136
#endif /* WITH_PROFINFO */
137137

138+
138139
#define Hd_val(val) (((header_t *) (val)) [-1]) /* Also an l-value. */
139140
#define Hd_op(op) (Hd_val (op)) /* Also an l-value. */
140141
#define Hd_bp(bp) (Hd_val (bp)) /* Also an l-value. */
@@ -194,6 +195,14 @@ bits 63 (64-P) (63-P) 10 9 8 7 0
194195
/* Also an l-value. */
195196
#endif
196197

198+
#define Unsafe_store_tag_val(dst, val) (Tag_val(dst) = val)
199+
/* Currently [Tag_val(dst)] is an lvalue, but in the future we may
200+
have to break this property by using explicit (relaxed) atomics to
201+
avoid undefined behaviors. [Unsafe_store_tag_val(dst, val)] is
202+
provided to avoid direct uses of [Tag_val(dst)] on the left of an
203+
assignment. The use of [Unsafe] emphasizes that the function
204+
may result in unsafe data races in a concurrent setting. */
205+
197206
/* The lowest tag for blocks containing no value. */
198207
#define No_scan_tag 251
199208

@@ -270,10 +279,14 @@ CAMLextern value caml_get_public_method (value obj, value tag);
270279
+ ((uintnat)(delta) << 1) + 1)
271280
#endif
272281

273-
/* This tag is used (with Forward_tag) to implement lazy values.
282+
/* This tag is used (with Forcing_tag & Forward_tag) to implement lazy values.
274283
See major_gc.c and stdlib/lazy.ml. */
275284
#define Lazy_tag 246
276285

286+
/* This tag is used (with Lazy_tag & Forward_tag) to implement lazy values.
287+
* See major_gc.c and stdlib/lazy.ml. */
288+
#define Forcing_tag 244
289+
277290
/* Another special case: variants */
278291
CAMLextern value caml_hash_variant(char const * tag);
279292

ocaml/runtime4/caml/weak.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ Caml_inline void caml_ephe_clean_partial (value v,
181181
value f = Forward_val (child);
182182
if (Is_block (f)) {
183183
if (!Is_in_value_area(f) || Tag_val (f) == Forward_tag
184-
|| Tag_val (f) == Lazy_tag || Tag_val (f) == Double_tag){
184+
|| Tag_val (f) == Lazy_tag || Tag_val (f) == Forcing_tag
185+
|| Tag_val (f) == Double_tag){
185186
/* Do not short-circuit the pointer. */
186187
}else{
187188
Field (v, i) = child = f;

ocaml/runtime4/extern.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ static void extern_rec(value v)
735735
value f = Forward_val (v);
736736
if (Is_block (f)
737737
&& (!Is_in_value_area(f) || Tag_val (f) == Forward_tag
738-
|| Tag_val (f) == Lazy_tag
738+
|| Tag_val (f) == Lazy_tag || Tag_val (f) == Forcing_tag
739739
#ifdef FLAT_FLOAT_ARRAY
740740
|| Tag_val (f) == Double_tag
741741
#endif

ocaml/runtime4/finalise.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ static void generic_final_register (struct finalisable *final, value f, value v)
361361
#ifdef FLAT_FLOAT_ARRAY
362362
|| Tag_val (v) == Double_tag
363363
#endif
364+
|| Tag_val (v) == Forcing_tag
364365
|| Tag_val (v) == Forward_tag) {
365366
caml_invalid_argument ("Gc.finalise");
366367
}

ocaml/runtime4/major_gc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ Caml_inline void mark_ephe_darken(struct mark_stack* stk, value v, mlsize_t i,
452452
if ((in_ephemeron && Is_long(f)) ||
453453
(Is_block (f)
454454
&& (!Is_in_value_area(f) || Tag_val (f) == Forward_tag
455-
|| Tag_val (f) == Lazy_tag
455+
|| Tag_val (f) == Lazy_tag || Tag_val (f) == Forcing_tag
456456
#ifdef FLAT_FLOAT_ARRAY
457457
|| Tag_val (f) == Double_tag
458458
#endif
@@ -534,7 +534,7 @@ static void mark_ephe_aux (struct mark_stack *stk, intnat *work,
534534
if (Is_long (f) ||
535535
(Is_block (f) &&
536536
(!Is_in_value_area(f) || Tag_val (f) == Forward_tag
537-
|| Tag_val (f) == Lazy_tag
537+
|| Tag_val (f) == Lazy_tag || Tag_val (f) == Forcing_tag
538538
#ifdef FLAT_FLOAT_ARRAY
539539
|| Tag_val (f) == Double_tag
540540
#endif

ocaml/runtime4/minor_gc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ void caml_oldify_one (value v, value *p)
259259
}
260260
}
261261
}
262-
if (!vv || ft == Forward_tag || ft == Lazy_tag
262+
if (!vv || ft == Forward_tag || ft == Lazy_tag || ft == Forcing_tag
263263
#ifdef FLAT_FLOAT_ARRAY
264264
|| ft == Double_tag
265265
#endif

ocaml/runtime4/misc.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -271,20 +271,3 @@ CAMLprim value caml_atomic_fetch_add(value ref, value incr)
271271
*p = Val_long(Long_val(ret) + Long_val(incr));
272272
return ret;
273273
}
274-
275-
/* Fake lazy operations - stdlib compatiblity with the 5 lazy implementation. */
276-
277-
CAMLprim value caml_lazy_update_to_forward(value v)
278-
{
279-
caml_failwith("Called caml_lazy_update_to_forward in runtime4: not supported.");
280-
}
281-
282-
CAMLprim value caml_lazy_reset_to_lazy(value v)
283-
{
284-
caml_failwith("Called caml_lazy_reset_to_lazy in runtime4: not supported.");
285-
}
286-
287-
CAMLprim value caml_lazy_update_to_forcing(value v)
288-
{
289-
caml_failwith("Called caml_lazy_update_to_forcing in runtime4: not supported.");
290-
}

ocaml/runtime4/obj.c

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,24 @@
3030
#include "caml/prims.h"
3131
#include "caml/signals.h"
3232

33-
CAMLprim value caml_obj_tag(value arg)
33+
static int obj_tag (value arg)
3434
{
3535
if (Is_long (arg)){
36-
return Val_int (1000); /* int_tag */
36+
return 1000; /* int_tag */
3737
}else if ((long) arg & (sizeof (value) - 1)){
38-
return Val_int (1002); /* unaligned_tag */
38+
return 1002; /* unaligned_tag */
3939
}else if (Is_in_value_area (arg)){
40-
return Val_int(Tag_val(arg));
40+
return Tag_val(arg);
4141
}else{
42-
return Val_int (1001); /* out_of_heap_tag */
42+
return 1001; /* out_of_heap_tag */
4343
}
4444
}
4545

46+
CAMLprim value caml_obj_tag(value arg)
47+
{
48+
return Val_int (obj_tag(arg));
49+
}
50+
4651
CAMLprim value caml_obj_set_tag (value arg, value new_tag)
4752
{
4853
Tag_val (arg) = Int_val (new_tag);
@@ -236,11 +241,9 @@ CAMLprim value caml_obj_add_offset (value v, value offset)
236241
return v + (unsigned long) Int32_val (offset);
237242
}
238243

239-
/* The following function is used in stdlib/lazy.ml.
240-
It is not written in OCaml because it must be atomic with respect
241-
to the GC.
242-
*/
243-
244+
/* The following functions are used to support lazy values. They are not
245+
* written in OCaml in order to ensure atomicity guarantees with respect to the
246+
* GC. */
244247
CAMLprim value caml_lazy_make_forward (value v)
245248
{
246249
CAMLparam1 (v);
@@ -251,6 +254,53 @@ CAMLprim value caml_lazy_make_forward (value v)
251254
CAMLreturn (res);
252255
}
253256

257+
static int obj_update_tag (value blk, int old_tag, int new_tag)
258+
{
259+
header_t hd;
260+
tag_t tag;
261+
262+
hd = Hd_val(blk);
263+
tag = Tag_hd(hd);
264+
265+
if (tag != old_tag) return 0;
266+
Unsafe_store_tag_val(blk, new_tag);
267+
return 1;
268+
}
269+
270+
CAMLprim value caml_lazy_reset_to_lazy (value v)
271+
{
272+
CAMLassert (Tag_val(v) == Forcing_tag);
273+
274+
obj_update_tag (v, Forcing_tag, Lazy_tag);
275+
return Val_unit;
276+
}
277+
278+
CAMLprim value caml_lazy_update_to_forward (value v)
279+
{
280+
CAMLassert (Tag_val(v) == Forcing_tag);
281+
282+
obj_update_tag (v, Forcing_tag, Forward_tag);
283+
return Val_unit;
284+
}
285+
286+
CAMLprim value caml_lazy_read_result (value v)
287+
{
288+
if (obj_tag(v) == Forward_tag)
289+
return Field(v,0);
290+
return v;
291+
}
292+
293+
CAMLprim value caml_lazy_update_to_forcing (value v)
294+
{
295+
if (Is_block(v) && /* Needed to ensure that we don't attempt to update the
296+
header of a integer value */
297+
obj_update_tag (v, Lazy_tag, Forcing_tag)) {
298+
return Val_int(0);
299+
} else {
300+
return Val_int(1);
301+
}
302+
}
303+
254304
/* For mlvalues.h and camlinternalOO.ml
255305
See also GETPUBMET in interp.c
256306
*/

0 commit comments

Comments
 (0)