Login

Compilation results

Most of these are undocumented ways to get extra information from the compiler about a program:

$ ocamlc -dlambda file.ml     # lambda representation, dumped to stderr
$ ocamlc -dparsetree file.ml  # parsed AST, to stderr
$ ocamlc -dtypedtree file.ml  # parsed AST, to stderr
$ ocamlopt -dcmm file.ml      # C-- IC, to stderr

For example, the C-- emitted from the following

let no_allocation _ = 'a'

let has_allocation n = n, n

let maybe_throws "123" = 'a'

seems to confirm the names of those functions:

(function{o4.ml:1,18-25} camlO4.no_allocation_11 (param/296: val) 195)

(function{o4.ml:3,19-27} camlO4.has_allocation_18 (n/290: val)
 (alloc{o4.ml:3,23-27} 2048 n/290 n/290))

(function{o4.ml:5,17-28} camlO4.maybe_throws_25 (param/292: val)
 (catch
   (let size/299 (>>u (load int (+a param/292 -8)) 10)
     (if (>= size/299 2) (exit 4)
       (let cell/298 (load_mut int (+a param/292 0))
         (if (== cell/298 288230376155066929) 195 (exit 4)))))
 with(4) (raise_notrace{o4.ml:5,17-22} "camlO4__Pmakeblock_46")))

NB. 195 = Char.code 'a' lsl 1 lor 1

And documented ways:

$ ocamlopt -S file.ml         # save asm in file.s
$ ocamlc -annot file.ml       # save inferred types in file.annot
$ ocamlobjinfo file.bc        # bytecode information

For very convenient profiling,

$ ocamlcp file.ml  # or ocamloptp
$ ./a.out
$ ocamlprof file.ml

ocamlprof reprints the file, retaining code, formatting, comments, while adding its own comments to show code path count. For example, the numbers in the following code were added by ocamlprof to show how this code handled Advent of Code 2005, day 5:

let ranges =
  let rec aux acc =
    (* 175 *) match read_line () with
    | "" -> (* 1 *) acc
    | line -> (* 174 *) aux (Scanf.sscanf line "%d-%d%!" Pair.make :: acc)
  in
  aux [] |> List.rev

let ids =
  let rec aux () =
    (* 1001 *) match read_line () with
    | line -> (* 1000 *) Scanf.sscanf line "%d" Fun.id :: aux ()
    | exception End_of_file -> (* 1 *) []
  in
  aux ()

Of course with native code, native tools apply:

$ objdump -dwr a.out   # dump reconstructed asm
$ ldd a.out            # show (ld.so mandatory) dynamic object dependencies
$ gdb ./a.out
$ strings a.out

-dlambda helps reveal the polymorphic comparisons in the following example:

let check_test (a : int array) (b : int array) : int array = 
  let compare x y = if x < y then 0 else 1 in (* calls caml_lessthan *)
  Array.init (Array.length a) (fun i -> compare a.(i) b.(i))

module Points1 = Set.Make (struct
  type t = int * int
  let compare = compare (* calls caml_compare *)
end)

module Points2 = Set.Make (struct
  type t = int * int
  let compare (x1, y1) (x2, y2) =
    match Int.compare x1 x2 with
    | 0 -> Int.compare y1 y2
    | c -> c
end)

AI: