{"action":"created","issue":{"url":"https://api.github.com/repos/ocaml/ocaml/issues/632","repository_url":"https://api.github.com/repos/ocaml/ocaml","labels_url":"https://api.github.com/repos/ocaml/ocaml/issues/632/labels{/name}","comments_url":"https://api.github.com/repos/ocaml/ocaml/issues/632/comments","events_url":"https://api.github.com/repos/ocaml/ocaml/issues/632/events","html_url":"https://github.com/ocaml/ocaml/pull/632","id":161624535,"number":632,"title":"Simplify identity matches","user":{"login":"smuenzel-js","id":20085597,"avatar_url":"https://avatars.githubusercontent.com/u/20085597?v=3","gravatar_id":"","url":"https://api.github.com/users/smuenzel-js","html_url":"https://github.com/smuenzel-js","followers_url":"https://api.github.com/users/smuenzel-js/followers","following_url":"https://api.github.com/users/smuenzel-js/following{/other_user}","gists_url":"https://api.github.com/users/smuenzel-js/gists{/gist_id}","starred_url":"https://api.github.com/users/smuenzel-js/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smuenzel-js/subscriptions","organizations_url":"https://api.github.com/users/smuenzel-js/orgs","repos_url":"https://api.github.com/users/smuenzel-js/repos","events_url":"https://api.github.com/users/smuenzel-js/events{/privacy}","received_events_url":"https://api.github.com/users/smuenzel-js/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":13,"created_at":"2016-06-22T08:42:35Z","updated_at":"2016-06-23T11:17:39Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ocaml/ocaml/pulls/632","html_url":"https://github.com/ocaml/ocaml/pull/632","diff_url":"https://github.com/ocaml/ocaml/pull/632.diff","patch_url":"https://github.com/ocaml/ocaml/pull/632.patch"},"body":"When we have a match of the following form:\r\n```\r\ntype t = X1 | X2 | X3 | X4 | X5 | X6 | X7\r\ntype t' = Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7\r\nmatch t with\r\n| X1 -> Y1\r\n| X2 -> Y2\r\n...\r\n```\r\nor\r\n``` \r\nmatch t with\r\n| X1 -> 0\r\n| X2 -> 1\r\n...\r\n```\r\nSimplify the match to the identity function. \r\n\r\nThese kinds of matches come up when you have a correspondence between a GADT and an ordinary type, and you convert from the GADT to the ordinary type.\r\nAnd they also come up when writing a GADT_to_int function (since, for example, typerep doesn't support GADTs)."},"comment":{"url":"https://api.github.com/repos/ocaml/ocaml/issues/comments/228019806","html_url":"https://github.com/ocaml/ocaml/pull/632#issuecomment-228019806","issue_url":"https://api.github.com/repos/ocaml/ocaml/issues/632","id":228019806,"user":{"login":"chambart","id":2196625,"avatar_url":"https://avatars.githubusercontent.com/u/2196625?v=3","gravatar_id":"","url":"https://api.github.com/users/chambart","html_url":"https://github.com/chambart","followers_url":"https://api.github.com/users/chambart/followers","following_url":"https://api.github.com/users/chambart/following{/other_user}","gists_url":"https://api.github.com/users/chambart/gists{/gist_id}","starred_url":"https://api.github.com/users/chambart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chambart/subscriptions","organizations_url":"https://api.github.com/users/chambart/orgs","repos_url":"https://api.github.com/users/chambart/repos","events_url":"https://api.github.com/users/chambart/events{/privacy}","received_events_url":"https://api.github.com/users/chambart/received_events","type":"User","site_admin":false},"created_at":"2016-06-23T11:17:39Z","updated_at":"2016-06-23T11:17:39Z","body":"Sorry for the contrived example (I replaced the match function by `Obj.magic` for readability).\r\n\r\nSo the basics of the problem is that OCaml needs to distinguish between integers and integers that are part of a type that can contain blocs. Simple constant integers are represented as `Const_int`, the other kind is `Const_pointer`. The `f` function matching `char` returning `t` allows to cast from simple integers (SI) to potentially pointers integers (PP). The unoptimized version is ok because it is explicitly rebuilding a PP, while the optimized one allows to cast from one type to the other transparently. This information is used by the GC when traversing the stack for collecting roots: SI are not traversed, while PP are since they could have been changed to pointers.\r\n\r\n```OCaml\r\ntype t = T | Bloc of int\r\n\r\nexternal p : t -> int = \"%int_as_pointer\" (* used to print pointers.\r\n                                             Please do not use for anything else ! *)\r\n\r\nlet f x = Obj.magic x    (* The optimized function *)\r\n[@@inline]\r\n\r\nlet error n =\r\n  let r = ref (f 'a') in (* The inliner will get rid of f, replacing the expression\r\n                            by the integer '97'.\r\n                            This reference being used with the right pattern will be\r\n                            converted to a mutable variable *)\r\n  let r' = ref (f 'a') in\r\n  for i = 0 to 1 do      (* This is a trick to circumvent a bugfix from 4.03 *)\r\n    r' := !r;            (* Move the content of mutable variable r to r'.\r\n                            Since r was not assigned to Bloc yet, it was not\r\n                            converted to a register potentially containing a\r\n                            pointer. So it will not turn r' into that kind of\r\n                            register.\r\n                            On the second round of the loop, this will contain\r\n                            (Bloc n) *)\r\n    r := Bloc n;\r\n  done;\r\n  print_int (p !r');     (* Print the address of (Bloc n) before the collection *)\r\n  (* r' is spilled to the stack *)\r\n  Gc.minor ();           (* (Bloc n) is fresh, hence allocated on the minor heap: this\r\n                            moves it to the major heap *)\r\n  (* r' is recovered from the stack *)\r\n  print_newline ();\r\n  print_int (p !r');     (* Print the address contained in r' after the collection.\r\n                            Since the content was promoted to the major heap, it should\r\n                            have changed, but here it didn't. *)\r\n  for i = 0 to 10000 do\r\n    ignore (Sys.opaque_identity (i, i));\r\n                         (* Fill the minor heap to overwrite the content pointed by 'r *)\r\n  done;\r\n  (match !r' with\r\n   | Bloc n ->\r\n     print_newline ();\r\n     print_int n;        (* Print something... should have been 42 *)\r\n     print_newline ()\r\n   | _ -> ());\r\n  [@@inline never]       (* Ensure that f is not inlined to avoid propagating the\r\n                            constant n. Otherwise (Bloc n) would have been statically\r\n                            allocated hence, couldn't move during a collection *)\r\n\r\nlet () =\r\n  error 42\r\n```\r\n\r\n```\r\n$ ocamlopt prob.ml -o prob\r\n$ ./prob \r\n69971463675692\r\n69971463675692\r\n16\r\n```"}}
{"actor":{"display_login":"chambart"}}