Inspector for OCaml runtime values
Use this library to inspect runtime integer and block values of OCaml. The following block tags are supported:
Tag Name | Tag Value |
---|---|
non-constant constructor tags | 0 ~ 245 |
closure tag | 247 |
object tag | 248 |
infix tag | 249 |
abstract tag | 251 |
string tag | 252 |
double tag | 253 |
double array tag | 254 |
custom tag | 255 |
Currently unsupported tags:
- lazy tag : 246
- forward tag : 250
The code is tested with OCaml 4.12.0. Blocks with a closure tag is structured differently in earlier OCaml versions and are not inspectable using this library.
Say you want to inspect the runtime representation of the expression
List.fold_right (plus 0) [1;2;3]
First, create a test file:
(* test.ml *)
open Oinsp
let plus : int -> int -> int -> int = fun x y z -> x + y + z
let _ = inspect @@ List.fold_right (plus 0) [1;2;3]
Then, put your test file and the library source files (oinsp.mli, oinsp.ml and Extoinsp.c) under the same directory, and execute the commands
ocamlopt -o out.opt Extoinsp.c oinsp.mli oinsp.ml test.ml
./out.opt
which calls the native-code compiler; or alternatively, execute the commands
ocamlc -o out.byt -custom Extoinsp.c oinsp.mli oinsp.ml test.ml
./out.byt
which calls the byte-code compiler. A text description of the runtime representation of the expression shall be displayed on your terminal.
The test.ml file gives numerous examples of using the library to inspect runtime values. To view these examples, change your working directory to the library directory, and
make clean && make
make
defaults to make native
; alternatively,
make clean && make byte
You can then compare the runtime representations with the source expressions, or compare the difference between using the bytecode and native-code compiler.
If you inspect "\255\252\000\000\000"
, you will see (no matter which compiler you use)
OCaml Value : 0X00007FABCB271A80
Header : 0X00000000000004FC
wo-size : 1
color : 0
string tag : 252
Field 0 :
Byte-0 : (#255)
Byte-1 : (#252)
Byte-2 : (#0)
Byte-3 : (#0)
Byte-4 : (#0)
Byte-5 : (#0)
Byte-6 : (#0)
Byte-7 : (#2)
OCaml string/bytes : (#255)(#252)(#0)(#0)(#0)
The header encodes the size of the block (excluding header, in words), the color for GC and the tag. This header structure is the same independent of the tag. As shown, the size (wo-size) is 1, that is, one machine word (on 64-bit architecture, a word has 8 bytes). The last byte of the last field means the number of bytes immediately before it which do not belong to the OCaml string.
As another example, if you inspect @@ List.fold_right (plus 0) [1;2;3]
once with the byte-code compiler and another time with the native-code compiler, you get different representations. In both cases, the header indicates there are five fields (wo-size : 5) and there is a closure tag; however, under byte-code compilation, field 2, 3 and 4 contain respectively repr. of List.fold_right
, (plus 0)
and [1;2;3]
; but under native-code compilation those fields contain resp. (plus 0)
, [1;2;3]
and List.fold_right
; there are further differences regarding arity and field organisation. For visual aide, different levels of field are indented by prefixing dots of different lengths; dots of the same length mean the same level.
Byte-code Compilation | Native-code Compilation |
|
|
-
The books Developing Applications in Objective Caml and Real World OCaml both have a chapter on interoperability with C, where you can find description of runtime values. The OCaml Reference Manual also has such a chapter. The first book (Dev. App. in O. Caml) focuses on runtime value representation under byte-code compilation.
-
There is a library to graphically display OCaml runtime values: ocaml-memgraph.