Skip to content

Commit 5be3cb8

Browse files
authored
flambda-backend: add the %get_header primitive (#1539)
1 parent 0006b3e commit 5be3cb8

17 files changed

+122
-5
lines changed

asmcomp/cmmgen.ml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ let rec transl env e =
642642
| Pasrbint _ | Pbintcomp (_, _) | Pstring_load _ | Pbytes_load _
643643
| Pbytes_set _ | Pbigstring_load _ | Pbigstring_set _
644644
| Punbox_float | Pbox_float _ | Punbox_int _ | Pbox_int _
645-
| Pbbswap _), _)
645+
| Pbbswap _ | Pget_header _), _)
646646
->
647647
fatal_error "Cmmgen.transl:prim"
648648
end
@@ -960,6 +960,8 @@ and transl_prim_1 env p arg dbg =
960960
| Pbswap16 ->
961961
tag_int (bswap16 (ignore_high_bit_int (untag_int
962962
(transl env arg) dbg)) dbg) dbg
963+
| Pget_header m ->
964+
box_int dbg Pnativeint m (get_header (transl env arg) dbg)
963965
| (Pfield_computed | Psequand | Psequor
964966
| Paddint | Psubint | Pmulint | Pandint
965967
| Porint | Pxorint | Plslint | Plsrint | Pasrint
@@ -1155,7 +1157,7 @@ and transl_prim_2 env p arg1 arg2 dbg =
11551157
| Pnegbint _ | Pbigarrayref (_, _, _, _) | Pbigarrayset (_, _, _, _)
11561158
| Pbigarraydim _ | Pbytes_set _ | Pbigstring_set _ | Pbbswap _
11571159
| Pprobe_is_enabled _
1158-
| Punbox_float | Pbox_float _ | Punbox_int _ | Pbox_int _
1160+
| Punbox_float | Pbox_float _ | Punbox_int _ | Pbox_int _ | Pget_header _
11591161
->
11601162
fatal_errorf "Cmmgen.transl_prim_2: %a"
11611163
Printclambda_primitives.primitive p
@@ -1216,7 +1218,7 @@ and transl_prim_3 env p arg1 arg2 arg3 dbg =
12161218
| Pbigarrayref (_, _, _, _) | Pbigarrayset (_, _, _, _) | Pbigarraydim _
12171219
| Pstring_load _ | Pbytes_load _ | Pbigstring_load _ | Pbbswap _
12181220
| Pprobe_is_enabled _
1219-
| Punbox_float | Pbox_float _ | Punbox_int _ | Pbox_int _
1221+
| Punbox_float | Pbox_float _ | Punbox_int _ | Pbox_int _ | Pget_header _
12201222
->
12211223
fatal_errorf "Cmmgen.transl_prim_3: %a"
12221224
Printclambda_primitives.primitive p

bytecomp/bytegen.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ let preserve_tailcall_for_prim = function
114114
true
115115
| Pbytes_to_string | Pbytes_of_string
116116
| Parray_to_iarray | Parray_of_iarray
117+
| Pget_header _
117118
| Pignore
118119
| Pgetglobal _ | Psetglobal _ | Pgetpredef _
119120
| Pmakeblock _ | Pmakefloatblock _
@@ -531,6 +532,7 @@ let comp_primitive p args =
531532
| Pbytes_of_string -> Kccall("caml_bytes_of_string", 1)
532533
| Parray_to_iarray -> Kccall("caml_iarray_of_array", 1)
533534
| Parray_of_iarray -> Kccall("caml_array_of_iarray", 1)
535+
| Pget_header _ -> Kccall("caml_get_header", 1)
534536
| Pobj_dup -> Kccall("caml_obj_dup", 1)
535537
(* The cases below are handled in [comp_expr] before the [comp_primitive] call
536538
(in the order in which they appear below),

lambda/lambda.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ type primitive =
246246
(* Jane Street extensions *)
247247
| Parray_to_iarray
248248
| Parray_of_iarray
249+
| Pget_header of alloc_mode
249250

250251
and integer_comparison =
251252
Ceq | Cne | Clt | Cgt | Cle | Cge
@@ -1462,7 +1463,7 @@ let primitive_may_allocate : primitive -> alloc_mode option = function
14621463
Some alloc_heap
14631464
| Pstring_load_16 _ | Pbytes_load_16 _ -> None
14641465
| Pstring_load_32 (_, m) | Pbytes_load_32 (_, m)
1465-
| Pstring_load_64 (_, m) | Pbytes_load_64 (_, m) -> Some m
1466+
| Pstring_load_64 (_, m) | Pbytes_load_64 (_, m) | Pget_header m -> Some m
14661467
| Pbytes_set_16 _ | Pbytes_set_32 _ | Pbytes_set_64 _ -> None
14671468
| Pbigstring_load_16 _ -> None
14681469
| Pbigstring_load_32 (_,m) | Pbigstring_load_64 (_,m) -> Some m
@@ -1576,6 +1577,7 @@ let primitive_result_layout (p : primitive) =
15761577
(* CR ncourant: use an unboxed int64 here when it exists *)
15771578
layout_any_value
15781579
| (Parray_to_iarray | Parray_of_iarray) -> layout_any_value
1580+
| Pget_header _ -> layout_boxedint Pnativeint
15791581

15801582
let compute_expr_layout free_vars_kind lam =
15811583
let rec compute_expr_layout kinds = function

lambda/lambda.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ type primitive =
199199
one; O(1) *)
200200
| Parray_of_iarray (* Unsafely reinterpret an immutable array as a mutable
201201
one; O(1) *)
202+
| Pget_header of alloc_mode
203+
(* Get the header of a block. This primitive is invalid if provided with an
204+
immediate value.
205+
Note: The GC color bits in the header are not reliable except for checking
206+
if the value is locally allocated *)
202207

203208
and integer_comparison =
204209
Ceq | Cne | Clt | Cgt | Cle | Cge

lambda/printlambda.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ let primitive ppf = function
484484

485485
| Parray_to_iarray -> fprintf ppf "array_to_iarray"
486486
| Parray_of_iarray -> fprintf ppf "array_of_iarray"
487+
| Pget_header m -> fprintf ppf "get_header%s" (alloc_kind m)
487488

488489
let name_of_primitive = function
489490
| Pbytes_of_string -> "Pbytes_of_string"
@@ -598,6 +599,7 @@ let name_of_primitive = function
598599
| Pbox_int _ -> "Pbox_int"
599600
| Parray_of_iarray -> "Parray_of_iarray"
600601
| Parray_to_iarray -> "Parray_to_iarray"
602+
| Pget_header _ -> "Pget_header"
601603

602604
let check_attribute ppf check =
603605
let check_property = function

lambda/tmc.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,7 @@ let rec choice ctx t =
921921
| Pbytes_set_16 _ | Pbytes_set_32 _ | Pbytes_set_64 _
922922
| Pbigstring_load_16 _ | Pbigstring_load_32 _ | Pbigstring_load_64 _
923923
| Pbigstring_set_16 _ | Pbigstring_set_32 _ | Pbigstring_set_64 _
924+
| Pget_header _
924925
| Pctconst _
925926
| Pbswap16
926927
| Pbbswap _

lambda/translprim.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ let lookup_primitive loc poly pos p =
418418
| "%array_of_iarray" -> Primitive (Parray_of_iarray, 1)
419419
| "%unbox_float" -> Primitive(Punbox_float, 1)
420420
| "%box_float" -> Primitive(Pbox_float mode, 1)
421+
| "%get_header" -> Primitive (Pget_header mode, 1)
421422
| s when String.length s > 0 && s.[0] = '%' ->
422423
raise(Error(loc, Unknown_builtin_primitive s))
423424
| _ -> External p
@@ -966,7 +967,7 @@ let lambda_primitive_needs_event_after = function
966967
| Pbytes_load_64 _ | Pbytes_set_16 _ | Pbytes_set_32 _ | Pbytes_set_64 _
967968
| Pbigstring_load_16 _ | Pbigstring_load_32 _ | Pbigstring_load_64 _
968969
| Pbigstring_set_16 _ | Pbigstring_set_32 _ | Pbigstring_set_64 _
969-
| Pbbswap _ | Pobj_dup -> true
970+
| Pbbswap _ | Pobj_dup | Pget_header _ -> true
970971

971972
| Pbytes_to_string | Pbytes_of_string
972973
| Parray_to_iarray | Parray_of_iarray

middle_end/clambda_primitives.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ type primitive =
128128
| Pbox_float of alloc_mode
129129
| Punbox_int of boxed_integer
130130
| Pbox_int of boxed_integer * alloc_mode
131+
| Pget_header of alloc_mode
131132

132133
and integer_comparison = Lambda.integer_comparison =
133134
Ceq | Cne | Clt | Cgt | Cle | Cge

middle_end/clambda_primitives.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ type primitive =
131131
| Pbox_float of alloc_mode
132132
| Punbox_int of boxed_integer
133133
| Pbox_int of boxed_integer * alloc_mode
134+
| Pget_header of alloc_mode
134135

135136
and integer_comparison = Lambda.integer_comparison =
136137
Ceq | Cne | Clt | Cgt | Cle | Cge

middle_end/convert_primitives.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ let convert (prim : Lambda.primitive) : Clambda_primitives.primitive =
158158
| Pbox_float m -> Pbox_float m
159159
| Punbox_int bi -> Punbox_int bi
160160
| Pbox_int (bi, m) -> Pbox_int (bi, m)
161+
| Pget_header m -> Pget_header m
161162
| Pobj_magic _
162163
| Pbytes_to_string
163164
| Pbytes_of_string

middle_end/internal_variable_names.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ let pxorint = "Pxorint"
176176
let pprobe_is_enabled = "Pprobe_is_enabled"
177177
let parray_of_iarray = "Parray_of_iarray"
178178
let parray_to_iarray = "Parray_to_iarray"
179+
let pget_header = "Pget_header"
179180
let pabsfloat_arg = "Pabsfloat_arg"
180181
let paddbint_arg = "Paddbint_arg"
181182
let paddfloat_arg = "Paddfloat_arg"
@@ -285,6 +286,7 @@ let pxorint_arg = "Pxorint_arg"
285286
let pprobe_is_enabled_arg = "Pprobe_is_enabled_arg"
286287
let parray_of_iarray_arg = "Parray_of_iarray_arg"
287288
let parray_to_iarray_arg = "Parray_to_iarray_arg"
289+
let pget_header_arg = "Pget_header_arg"
288290
let raise = "raise"
289291
let raise_arg = "raise_arg"
290292
let read_mutable = "read_mutable"
@@ -439,6 +441,7 @@ let of_primitive : Lambda.primitive -> string = function
439441
| Pbox_int _ -> pbox_int
440442
| Parray_of_iarray -> parray_of_iarray
441443
| Parray_to_iarray -> parray_to_iarray
444+
| Pget_header _ -> pget_header
442445

443446
let of_primitive_arg : Lambda.primitive -> string = function
444447
| Pbytes_of_string -> pbytes_of_string_arg
@@ -553,3 +556,4 @@ let of_primitive_arg : Lambda.primitive -> string = function
553556
| Pbox_int _ -> pbox_int_arg
554557
| Parray_of_iarray -> parray_of_iarray_arg
555558
| Parray_to_iarray -> parray_to_iarray_arg
559+
| Pget_header _ -> pget_header_arg

middle_end/printclambda_primitives.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,4 @@ let primitive ppf (prim:Clambda_primitives.primitive) =
259259
| Pbox_int (bi, m) ->
260260
fprintf ppf "box_%s.%s" (boxed_integer_name bi) (alloc_kind m)
261261
| Punbox_int bi -> fprintf ppf "unbox_%s" (boxed_integer_name bi)
262+
| Pget_header m -> fprintf ppf "get_header.%s" (alloc_kind m)

middle_end/semantics_of_primitives.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ let for_primitive (prim : Clambda_primitives.primitive) =
144144
| Psequor ->
145145
(* Removed by [Closure_conversion] in the flambda pipeline. *)
146146
No_effects, No_coeffects
147+
| Pget_header _ -> No_effects, No_coeffects
147148

148149
type return_type =
149150
| Float
@@ -270,3 +271,4 @@ let may_locally_allocate (prim:Clambda_primitives.primitive) : bool =
270271
| Psequor ->
271272
false
272273
| Pprobe_is_enabled _ -> false
274+
| Pget_header m -> is_local_alloc m

runtime/obj.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ CAMLprim value caml_obj_is_local(value blk)
7373
return Val_int(Is_block(blk) && Color_hd(Hd_val(blk)) == Local_unmarked);
7474
}
7575

76+
CAMLprim value caml_get_header(value blk)
77+
{
78+
// undefined behaviour if blk is not a block
79+
intnat r = Hd_val(blk);
80+
return caml_copy_nativeint(r);
81+
}
82+
7683
/* [size] is a value encoding a number of blocks */
7784
CAMLprim value caml_obj_block(value tag, value size)
7885
{
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
None false
2+
Some(wosize=1,color=0,tag=252) false
3+
Some(wosize=1,color=0,tag=0) false

testsuite/tests/lib-obj/get_header.ml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
(* TEST
2+
* native
3+
reference = "${test_source_directory}/get_header.opt.reference"
4+
* bytecode
5+
reference = "${test_source_directory}/get_header.byte.reference"
6+
*)
7+
8+
external repr : ('a[@local_opt]) -> (Obj.t[@local_opt]) = "%identity"
9+
external get_header_unsafe : (Obj.t[@local_opt]) -> nativeint = "%get_header"
10+
external is_int : (Obj.t[@local_opt]) -> bool = "%obj_is_int"
11+
12+
let get_header (local_ repr) =
13+
if is_int repr then
14+
None
15+
else
16+
Some (get_header_unsafe repr)
17+
18+
type header = {
19+
wosize : int;
20+
color : int;
21+
tag : int
22+
}
23+
24+
let parse_header : nativeint -> header =
25+
fun header ->
26+
let wosize =
27+
Nativeint.to_int
28+
(Nativeint.shift_right_logical header 10)
29+
in
30+
31+
let color =
32+
0x3 land
33+
(Nativeint.to_int (Nativeint.shift_right_logical header 8))
34+
in
35+
36+
let tag = 0xff land (Nativeint.to_int header) in
37+
38+
{wosize; color; tag}
39+
40+
let get_header_parsed repr =
41+
Option.map parse_header (get_header repr)
42+
43+
let print_header ppf header =
44+
let {wosize; color; tag} = header in
45+
Format.fprintf ppf "wosize=%i,color=%i,tag=%i" wosize color tag
46+
47+
let print_maybe_header ppf header =
48+
match header with
49+
| None -> Format.fprintf ppf "None"
50+
| Some header -> Format.fprintf ppf "Some(%a)" print_header header
51+
52+
let is_local repr =
53+
match get_header_parsed repr with
54+
| None -> false
55+
| Some {color; _} -> color = 2
56+
57+
(* immediate *)
58+
let () =
59+
let x = 42 in
60+
let rp = repr x in
61+
Format.printf "%a %a\n" print_maybe_header (get_header_parsed rp)
62+
Format.pp_print_bool (is_local rp)
63+
64+
(* global*)
65+
let () =
66+
let s = "hello" in
67+
let _r = ref s in
68+
let rp = repr s in
69+
Format.printf "%a %a\n" print_maybe_header (get_header_parsed rp)
70+
Format.pp_print_bool (is_local rp)
71+
72+
(* local *)
73+
let foo x =
74+
let local_ s = ref x in
75+
let rp = repr s in
76+
Format.printf "%a %a\n" print_maybe_header (get_header_parsed rp)
77+
Format.pp_print_bool (is_local rp)
78+
79+
let () = foo 42
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
None false
2+
Some(wosize=1,color=3,tag=252) false
3+
Some(wosize=1,color=2,tag=0) true

0 commit comments

Comments
 (0)