This is an automated email from the git hooks/post-receive script.

glondu pushed a commit to branch master
in repository atdgen.

commit f74d05850780d750110bb44099b6151f62d16f47
Author: Stephane Glondu <st...@glondu.net>
Date:   Thu Aug 4 11:14:57 2016 +0200

    Imported Upstream version 1.9.1
---
 src/Makefile             |   2 +-
 src/ag_main.ml           |   8 +--
 src/ag_ob_emit.ml        |  73 ++++++++++++++++-----------
 src/ag_oj_emit.ml        |  17 +++++--
 src/ag_ov_emit.ml        |   1 +
 src/ag_ox_emit.mli       |  32 ++++++++++++
 test/test_atdgen_main.ml | 127 ++++++++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 223 insertions(+), 37 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index c25441a..328539e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,4 +1,4 @@
-VERSION = 1.9.0
+VERSION = 1.9.1
 ifeq "$(shell ocamlc -config |grep os_type)" "os_type: Win32"
 EXE=.exe
 else
diff --git a/src/ag_main.ml b/src/ag_main.ml
index 3a87e44..5455c92 100644
--- a/src/ag_main.ml
+++ b/src/ag_main.ml
@@ -54,8 +54,8 @@ let parse_ocaml_version () =
   else
     None
 
-let get_default_name_overlap () =
-  match parse_ocaml_version () with
+let get_default_name_overlap ocaml_version =
+  match ocaml_version with
   | Some (major, minor) when major < 4 -> false
   | Some (4, 0) -> false
   | _ -> true
@@ -77,7 +77,8 @@ let main () =
   let unknown_field_handler = ref None in
   let constr_mismatch_handler = ref None in
   let type_aliases = ref None in
-  let name_overlap = ref (get_default_name_overlap ()) in
+  let ocaml_version = parse_ocaml_version () in
+  let name_overlap = ref (get_default_name_overlap ocaml_version) in
   let set_opens s =
     let l = Str.split (Str.regexp " *, *\\| +") s in
     opens := List.rev_append l !opens
@@ -435,6 +436,7 @@ Recommended usage: %s (-t|-b|-j|-v|-dep|-list) example.atd" 
Sys.argv.(0) in
           ~pos_lnum: !pos_lnum
           ~type_aliases
           ~force_defaults
+          ~ocaml_version
           ~name_overlap: !name_overlap
           atd_file ocaml_prefix
 
diff --git a/src/ag_ob_emit.ml b/src/ag_ob_emit.ml
index 71a11f0..ead7476 100644
--- a/src/ag_ob_emit.ml
+++ b/src/ag_ob_emit.ml
@@ -730,7 +730,7 @@ and make_table_writer deref tagged list_kind x =
     main
 
 
-let study_record deref fields =
+let study_record ~ocaml_version deref fields =
   let field_assignments =
     List.fold_right (
       fun (x, name, default, opt, unwrap) field_assignments ->
@@ -738,7 +738,11 @@ let study_record deref fields =
           match default with
               None ->
                 assert (not opt);
-                "Obj.magic 0.0"
+                begin match ocaml_version with
+                  | Some (maj, min) when (maj > 4 || maj = 4 && min >= 3) ->
+                      "Obj.magic (Sys.opaque_identity 0.0)"
+                  | _ -> "Obj.magic 0.0"
+                end
             | Some s ->
                 s
         in
@@ -890,7 +894,7 @@ let wrap_bodies ~tagged l =
 
 
 let rec make_reader
-    deref ~tagged ?type_annot (x : ob_mapping)
+    deref ~tagged ~ocaml_version ?type_annot (x : ob_mapping)
     : Ag_indent.t list =
   match x with
       `Unit _
@@ -918,7 +922,8 @@ let rec make_reader
                   Array.to_list (
                     Array.map
                       (fun x ->
-                        `Inline (make_variant_reader deref type_annot tick x)
+                        `Inline (make_variant_reader ~ocaml_version
+                                   deref type_annot tick x)
                       )
                       a
                   )
@@ -937,11 +942,11 @@ let rec make_reader
            | `Object ->
                error loc "Sorry, OCaml objects are not supported"
         );
-        let body = make_record_reader deref ~tagged type_annot a o in
+        let body = make_record_reader deref ~ocaml_version ~tagged type_annot 
a o in
         wrap_body ~tagged Bi_io.record_tag body
 
     | `Tuple (loc, a, `Tuple, `Tuple) ->
-        let body = make_tuple_reader deref ~tagged a in
+        let body = make_tuple_reader deref ~ocaml_version ~tagged a in
         wrap_body ~tagged Bi_io.tuple_tag body
 
     | `List (loc, x, `List o, `List b) ->
@@ -953,7 +958,7 @@ let rec make_reader
                in
                [
                  `Line (f ^ " (");
-                 `Block (make_reader deref ~tagged:false x);
+                 `Block (make_reader deref ~ocaml_version ~tagged:false x);
                  `Line ")";
                ]
            | `Array, `Array ->
@@ -963,12 +968,13 @@ let rec make_reader
                in
                [
                  `Line (f ^ " (");
-                 `Block (make_reader deref ~tagged:false x);
+                 `Block (make_reader deref ~ocaml_version ~tagged:false x);
                  `Line ")";
                ]
            | list_kind, `Table ->
                (* Support table format and regular array format *)
-               let body1 = make_table_reader deref loc list_kind x in
+               let body1 =
+                 make_table_reader ~ocaml_version deref loc list_kind x in
                let body2 =
                  let f =
                    match list_kind with
@@ -977,7 +983,7 @@ let rec make_reader
                  in
                  [
                    `Line (f ^ " (");
-                   `Block (make_reader deref ~tagged:false x);
+                   `Block (make_reader deref ~tagged:false ~ocaml_version x);
                    `Line ") ib";
                  ]
                in
@@ -996,7 +1002,7 @@ let rec make_reader
               `Line "Some (";
               `Block [
                 `Line "(";
-                `Block (make_reader deref ~tagged:true x);
+                `Block (make_reader deref ~tagged:true ~ocaml_version x);
                 `Line ")";
                  `Block [ `Line "ib"];
               ];
@@ -1009,7 +1015,7 @@ let rec make_reader
         wrap_body ~tagged Bi_io.num_variant_tag body
 
     | `Wrap (loc, x, `Wrap o, `Wrap) ->
-        let simple_reader = make_reader deref ~tagged x in
+        let simple_reader = make_reader deref ~tagged ~ocaml_version x in
         (match o with
             None -> simple_reader
           | Some { Ag_ocaml.ocaml_wrap } ->
@@ -1035,7 +1041,7 @@ let rec make_reader
     | _ -> assert false
 
 
-and make_variant_reader deref type_annot tick x : Ag_indent.t list =
+and make_variant_reader ~ocaml_version deref type_annot tick x : Ag_indent.t 
list =
   let o =
     match x.var_arepr, x.var_brepr with
         `Variant o, `Variant -> o
@@ -1054,7 +1060,7 @@ and make_variant_reader deref type_annot tick x : 
Ag_indent.t list =
           `Block [
             `Block [
               `Line "(";
-              `Block (make_reader deref ~tagged:true v);
+              `Block (make_reader deref ~tagged:true ~ocaml_version v);
               `Line ") ib";
             ];
             `Line (sprintf ")%s)" (Ag_ox_emit.insert_annot type_annot));
@@ -1062,11 +1068,11 @@ and make_variant_reader deref type_annot tick x : 
Ag_indent.t list =
         ]
 
 and make_record_reader
-    deref ~tagged type_annot
+    deref ~ocaml_version ~tagged type_annot
     a record_kind =
   let fields = get_fields deref a in
   let init_fields, init_bits, set_bit, check_bits, create_record =
-    study_record deref fields
+    study_record ~ocaml_version deref fields
   in
 
   let body =
@@ -1090,7 +1096,7 @@ and make_record_reader
           let read_value =
             [
               `Line "(";
-              `Block (make_reader deref ~tagged:true f_value);
+              `Block (make_reader deref ~tagged:true ~ocaml_version f_value);
               `Line ") ib"
             ]
           in
@@ -1128,7 +1134,7 @@ and make_record_reader
   ]
 
 
-and make_tuple_reader deref ~tagged a =
+and make_tuple_reader deref ~tagged ~ocaml_version a =
   let cells =
     Array.map (
       fun x ->
@@ -1157,7 +1163,9 @@ and make_tuple_reader deref ~tagged a =
       Array.to_list (
         Array.mapi (
           fun i (x, default) ->
-            let read_value = make_reader deref ~tagged:true x.cel_value in
+            let read_value =
+              make_reader deref ~ocaml_version ~tagged:true
+                x.cel_value in
             let get_value =
               if i < min_length then
                 [
@@ -1212,7 +1220,7 @@ and make_tuple_reader deref ~tagged a =
   ]
 
 
-and make_table_reader deref loc list_kind x =
+and make_table_reader deref ~ocaml_version loc list_kind x =
   let empty_list, to_list =
     match list_kind with
         `List -> "[ ]", (fun s -> "Array.to_list " ^ s)
@@ -1231,7 +1239,7 @@ and make_table_reader deref loc list_kind x =
           error loc "Not a list or array of records"
   in
   let init_fields, init_bits, set_bit, check_bits, create_record =
-    study_record deref fields
+    study_record ~ocaml_version deref fields
   in
   let cases =
     Array.to_list (
@@ -1244,7 +1252,7 @@ and make_table_reader deref loc list_kind x =
               `Line "let read =";
               `Block [
                 `Line "(";
-                `Block (make_reader deref ~tagged:false x.f_value);
+                `Block (make_reader deref ~tagged:false ~ocaml_version 
x.f_value);
                 `Line ")";
                 `Block [ `Line "tag" ]
               ];
@@ -1339,7 +1347,8 @@ let make_ocaml_biniou_writer ~original_types deref is_rec 
let1 let2 def =
     ]
   ]
 
-let make_ocaml_biniou_reader ~original_types deref is_rec let1 let2 def =
+let make_ocaml_biniou_reader ~original_types ~ocaml_version
+    deref is_rec let1 let2 def =
   let x = match def.def_value with None -> assert false | Some x -> x in
   let name = def.def_name in
   let type_constraint = Ag_ox_emit.get_type_constraint ~original_types def in
@@ -1352,8 +1361,9 @@ let make_ocaml_biniou_reader ~original_types deref is_rec 
let1 let2 def =
     | true -> Some type_constraint
     | false -> None
   in
-  let get_reader_expr = make_reader deref ~tagged:false ?type_annot x in
-  let read_expr = make_reader deref ~tagged:true ?type_annot x in
+  let get_reader_expr =
+    make_reader deref ~tagged:false ~ocaml_version ?type_annot x in
+  let read_expr = make_reader deref ~tagged:true ~ocaml_version ?type_annot x 
in
   let eta_expand1 = is_rec && not (Ag_ox_emit.is_function get_reader_expr) in
   let eta_expand2 = is_rec && not (Ag_ox_emit.is_function read_expr) in
   let extra_param1, extra_args1 =
@@ -1389,7 +1399,8 @@ let get_let ~is_rec ~is_first =
     else "let", "let"
   else "and", "and"
 
-let make_ocaml_biniou_impl ~with_create ~original_types buf deref defs =
+let make_ocaml_biniou_impl ~with_create ~original_types ~ocaml_version
+    buf deref defs =
 
   let ll =
     List.map (
@@ -1407,7 +1418,7 @@ let make_ocaml_biniou_impl ~with_create ~original_types 
buf deref defs =
           map (
             fun is_first def ->
               let let1, let2 = get_let ~is_rec ~is_first in
-              make_ocaml_biniou_reader
+              make_ocaml_biniou_reader ~ocaml_version
                 ~original_types deref is_rec let1 let2 def
           ) l
         in
@@ -1456,6 +1467,7 @@ let make_mli
 
 let make_ml
     ~header ~opens ~with_typedefs ~with_create ~with_fundefs ~original_types
+    ~ocaml_version
     ocaml_typedefs deref defs =
   let buf = Buffer.create 1000 in
   bprintf buf "%s\n" header;
@@ -1465,7 +1477,9 @@ let make_ml
   if with_typedefs && with_fundefs then
     bprintf buf "\n";
   if with_fundefs then
-    make_ocaml_biniou_impl ~with_create ~original_types buf deref defs;
+    make_ocaml_biniou_impl
+      ~with_create ~original_types ~ocaml_version
+      buf deref defs;
   Buffer.contents buf
 
 let make_ocaml_files
@@ -1479,6 +1493,7 @@ let make_ocaml_files
     ~type_aliases
     ~force_defaults
     ~name_overlap
+    ~ocaml_version
     ~pp_convs
     atd_file out =
   let ((head, m0), _) =
@@ -1528,7 +1543,7 @@ let make_ocaml_files
   in
   let ml =
     make_ml ~header ~opens ~with_typedefs ~with_create ~with_fundefs
-      ~original_types ocaml_typedefs
+      ~original_types ~ocaml_version ocaml_typedefs
       (Ag_mapping.make_deref defs) defs
   in
   Ag_ox_emit.write_ocaml out mli ml
diff --git a/src/ag_oj_emit.ml b/src/ag_oj_emit.ml
index 6463fec..244a78c 100644
--- a/src/ag_oj_emit.ml
+++ b/src/ag_oj_emit.ml
@@ -34,6 +34,8 @@ type param = {
   preprocess_input : string option;
     (* intended for UTF-8 validation *)
 
+  ocaml_version: (int * int) option;
+
 }
 
 
@@ -739,8 +741,11 @@ and make_record_writer p a record_kind =
     `Line "Bi_outbuf.add_char ob '}';";
   ]
 
-let study_record deref fields =
-  let unset_field_value = "Obj.magic 0.0" in
+let study_record p fields =
+  let unset_field_value = match p.ocaml_version with
+    | Some (maj, min) when (maj > 4 || maj = 4 && min >= 3) ->
+      "Obj.magic (Sys.opaque_identity 0.0)"
+    | _ -> "Obj.magic 0.0" in
 
   let _, field_assignments =
     Array.fold_right (fun field (i, field_assignments) ->
@@ -1233,7 +1238,7 @@ and make_deconstructed_reader p loc fields set_bit =
 and make_record_reader p type_annot loc a record_kind =
   let fields = get_fields p a in
   let init_fields, init_bits, set_bit, check_bits, create_record =
-    study_record p.deref fields
+    study_record p fields
   in
 
   let read_field =
@@ -1617,6 +1622,7 @@ let get_let ~is_rec ~is_first =
 let make_ocaml_json_impl
     ~std ~unknown_field_handler ~constr_mismatch_handler
     ~with_create ~force_defaults ~preprocess_input ~original_types
+    ~ocaml_version
     buf deref defs =
   let p = {
     deref = deref;
@@ -1625,6 +1631,7 @@ let make_ocaml_json_impl
     constr_mismatch_handler = constr_mismatch_handler;
     force_defaults = force_defaults;
     preprocess_input;
+    ocaml_version;
   } in
   let ll =
     List.map (
@@ -1692,6 +1699,7 @@ let make_ml
     ~header ~opens ~with_typedefs ~with_create ~with_fundefs
     ~std ~unknown_field_handler ~constr_mismatch_handler
     ~force_defaults ~preprocess_input ~original_types
+    ~ocaml_version
     ocaml_typedefs deref defs =
   let buf = Buffer.create 1000 in
   bprintf buf "%s\n" header;
@@ -1704,6 +1712,7 @@ let make_ml
     make_ocaml_json_impl
       ~std ~unknown_field_handler ~constr_mismatch_handler
       ~with_create ~force_defaults ~preprocess_input ~original_types
+      ~ocaml_version
       buf deref defs;
   Buffer.contents buf
 
@@ -1722,6 +1731,7 @@ let make_ocaml_files
     ~force_defaults
     ~preprocess_input
     ~name_overlap
+    ~ocaml_version
     ~pp_convs
     atd_file out =
   let ((head, m0), _) =
@@ -1772,6 +1782,7 @@ let make_ocaml_files
     make_ml ~header ~opens ~with_typedefs ~with_create ~with_fundefs
       ~std ~unknown_field_handler ~constr_mismatch_handler
       ~force_defaults ~preprocess_input ~original_types
+      ~ocaml_version
       ocaml_typedefs (Ag_mapping.make_deref defs) defs
   in
   Ag_ox_emit.write_ocaml out mli ml
diff --git a/src/ag_ov_emit.ml b/src/ag_ov_emit.ml
index de9d803..154ae04 100644
--- a/src/ag_ov_emit.ml
+++ b/src/ag_ov_emit.ml
@@ -473,6 +473,7 @@ let make_ocaml_files
     ~type_aliases
     ~force_defaults
     ~name_overlap
+    ~ocaml_version
     ~pp_convs
     atd_file out =
   let ((head, m0), _) =
diff --git a/src/ag_ox_emit.mli b/src/ag_ox_emit.mli
new file mode 100644
index 0000000..ea3d1d3
--- /dev/null
+++ b/src/ag_ox_emit.mli
@@ -0,0 +1,32 @@
+type 'a expr = (Ag_ocaml.atd_ocaml_repr, 'a) Ag_mapping.mapping
+type 'a def = (Ag_ocaml.atd_ocaml_repr, 'a) Ag_mapping.def
+type 'a grouped_defs = (bool * 'a def list) list
+
+val get_full_type_name : (_, _) Ag_mapping.def -> string
+
+val is_exportable : (_, _) Ag_mapping.def -> bool
+
+val make_record_creator
+  : ((Ag_ocaml.atd_ocaml_repr, 'a) Ag_mapping.mapping
+     -> (Ag_ocaml.atd_ocaml_repr, 'b) Ag_mapping.mapping)
+  -> (Ag_ocaml.atd_ocaml_repr, 'a) Ag_mapping.def
+  -> string * string
+
+val opt_annot : string option -> string -> string
+
+val opt_annot_def : string option -> string -> string
+
+val insert_annot : string option -> string
+
+val get_type_constraint
+  : original_types:(string, string * int) Hashtbl.t
+  -> ('a, 'b) Ag_mapping.def
+  -> string
+
+val is_function : Ag_indent.t list -> bool
+
+val needs_type_annot : _ expr -> bool
+
+val check : _ grouped_defs -> unit
+
+val write_ocaml : [< `Files of string | `Stdout ] -> string -> string -> unit
diff --git a/test/test_atdgen_main.ml b/test/test_atdgen_main.ml
index 1a475a5..732f32b 100644
--- a/test/test_atdgen_main.ml
+++ b/test/test_atdgen_main.ml
@@ -63,10 +63,135 @@ let test_missing_tuple = (123, 4.56)
 type internals1 = { int : int }
 type internals2 = { float : float }
 
+  (* Obj.magic 0.0, opaque_identity, and record fields
+
+     Instead of using options (which may allocate), atdgen uses
+     a default value for references that denote record fields that may
+     not yet have been deserialized.
+
+     For example, consider the following example in the test.ml
+     generated code:
+
+type extended = {
+  b0x: int;
+  b1x: bool;
+  b2x: string;
+  b3x: string option;
+  b4x: string option;
+  b5x: float
+}
+
+let get_extended_reader = (
+  fun tag ->
+    if tag <> 21 then Ag_ob_run.read_error () else
+      fun ib ->
+        let field_b0x = ref (Obj.magic (Sys.opaque_identity 0.0)) in
+        let field_b1x = ref (Obj.magic (Sys.opaque_identity 0.0)) in
+        let field_b2x = ref (Obj.magic (Sys.opaque_identity 0.0)) in
+        let field_b3x = ref (None) in
+        let field_b4x = ref (Obj.magic (Sys.opaque_identity 0.0)) in
+        let field_b5x = ref (0.5) in
+        let bits0 = ref 0 in
+        let len = Bi_vint.read_uvint ib in
+        for i = 1 to len do
+          match Bi_io.read_field_hashtag ib with
+            | 21902 ->
+              field_b0x := (
+                (
+                  Ag_ob_run.read_int
+                ) ib
+              );
+              bits0 := !bits0 lor 0x1;
+            | 21903 ->
+              field_b1x := (
+                (
+                  Ag_ob_run.read_bool
+                ) ib
+              );
+              bits0 := !bits0 lor 0x2;
+           (* ... CODE ELIDED HERE ... *)
+            | 21907 ->
+              field_b5x := (
+                (
+                  Ag_ob_run.read_float64
+                ) ib
+              );
+            | _ -> Bi_io.skip ib
+        done;
+        if !bits0 <> 0xf then Ag_ob_run.missing_fields
+          [| !bits0 |] [| "b0"; "b1"; "b2"; "b4" |];
+        (
+          {
+            b0x = !field_b0x;
+            b1x = !field_b1x;
+            b2x = !field_b2x;
+            b3x = !field_b3x;
+            b4x = !field_b4x;
+            b5x = !field_b5x;
+          }
+         : extended)
+
+     # Why Obj.magic?
+
+     At code generation time we do not have a default
+     value for the type of this field (we don't know what the type
+     is), so we create one out of thin air with Obj.magic
+
+     # Why 0.0?
+
+     Atdgen does not run the type-checker, so it does not a-priori
+     know if the field type is float (it may be a type alias of
+     "float" or even depend on a functor parameter).
+
+     If the type *is* float and the type-checker notices it
+     statically, then it may allocate an unboxed float reference, and
+     in particular unbox the default value passed at reference create
+     time. If this default value was *not* a float, then the code could
+     segfault. So in this case we must use a float value.
+
+     If the type is *not* float, then passing a float value is still
+     correct: the compiler will not try to unbox it, so a (word-sized)
+     pointer will be stored in the reference.
+
+     # Why Sys.opaque_identity?
+
+     Starting from 4.03, the compiler is more clever at assuming
+     things from values. When it sees the constant 0.0, it will infer
+     in particular that the reference contains a float (so it may
+     decide to unbox it!), etc. Notice that the compiler makes just
+     the same assumptions about (Obj.magic 0.0) than about 0.0, the
+     magic changes the type but not the value.
+
+     Also in 4.03, the Sys.opaque_identity function was added in the
+     Sys module; it is a compiler primitive of type ('a -> 'a) that
+     prevents the compiler from assuming anything about its return value.
+
+     In practice, using Sys.opaque_identity here avoids the segfault
+     that happened without it on 4.03. Note that this may not be
+     enough; in particular, (Sys.opaque_identity 0.0) is still
+     recognizeably a value of "float" type to the compiler (only the
+     value is unknown), so it would be legal for the compiler to still
+     decide to unbox in the future!
+
+     The long-term solution would be to stop using these unsafe
+     Obj.magic and use an option type to store the reference fields in
+     this case. This would be a more invasive change to the
+     implementation.
+  *)
+
 let test_ocaml_internals () =
   section "ocaml internals";
 
-  let int = ref (Obj.magic 0.0) in
+  let opaque_identity =
+    (* neat trick to fallback to just the identity if we are using
+       a <4.03 version and Sys.opaque_identity is not available; found
+       in
+         
https://github.com/LaurentMazare/tensorflow-ocaml/commit/111b4727cec992bab8bc67c22ccc8c31942ffbb2
 *)
+    let opaque_identity x = x in
+    ignore opaque_identity;
+    let open Sys in opaque_identity in
+
+  let int = ref (Obj.magic (opaque_identity 0.0)) in
   Gc.compact ();
   int := 123;
   Gc.compact ();

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-ocaml-maint/packages/atdgen.git

_______________________________________________
Pkg-ocaml-maint-commits mailing list
Pkg-ocaml-maint-commits@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-ocaml-maint-commits

Reply via email to