98 lines
3.2 KiB
OCaml
98 lines
3.2 KiB
OCaml
(***********************************************************************)
|
|
(* *)
|
|
(* Objective Caml *)
|
|
(* *)
|
|
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
|
|
(* *)
|
|
(* Copyright 1996 Institut National de Recherche en Informatique et *)
|
|
(* Automatique. Distributed only by permission. *)
|
|
(* *)
|
|
(***********************************************************************)
|
|
|
|
(* $Id$ *)
|
|
|
|
(* The "trace" facility *)
|
|
|
|
open Format
|
|
open Misc
|
|
open Longident
|
|
open Types
|
|
open Printval
|
|
open Toploop
|
|
|
|
type traced_function =
|
|
{ path: Path.t;
|
|
closure: Obj.t;
|
|
initial_closure: Obj.t;
|
|
instrumented_fun: Obj.t }
|
|
|
|
let traced_functions = ref ([] : traced_function list)
|
|
|
|
(* Check if a function is already traced *)
|
|
|
|
let is_traced clos =
|
|
let rec is_traced = function
|
|
[] -> None
|
|
| tf :: rem -> if tf.closure == clos then Some tf.path else is_traced rem
|
|
in is_traced !traced_functions
|
|
|
|
(* Make a copy of a closure *)
|
|
|
|
let copy_closure cls =
|
|
let sz = Obj.size cls in
|
|
let nw = Obj.new_block 250 sz in
|
|
for i = 0 to sz - 1 do Obj.set_field nw i (Obj.field cls i) done;
|
|
nw
|
|
|
|
(* Overwrite the code field of a closure by another *)
|
|
|
|
let overwrite_closure dst src =
|
|
Obj.set_field dst 0 (Obj.field src 0)
|
|
|
|
(* Return a closure that performs as the given closure, but also
|
|
traces its execution. *)
|
|
|
|
let rec instrument_closure env name clos_typ =
|
|
match (Ctype.repr(Ctype.expand_root env clos_typ)).desc with
|
|
Tarrow(t1, t2) ->
|
|
let starred_name =
|
|
match name with
|
|
Lident s -> Lident(s ^ "*")
|
|
| Ldot(lid, s) -> Ldot(lid, s ^ "*")
|
|
| Lapply(l1, l2) -> fatal_error "Trace.instrument_closure" in
|
|
let trace_res = instrument_closure env starred_name t2 in
|
|
(fun clos_val ->
|
|
Obj.repr(fun arg ->
|
|
open_hovbox 2;
|
|
Printtyp.longident name; print_string " <--"; print_space();
|
|
print_value !toplevel_env arg t1; close_box(); print_newline();
|
|
try
|
|
let res = (Obj.magic clos_val : Obj.t -> Obj.t)(arg) in
|
|
open_hovbox 2;
|
|
Printtyp.longident name; print_string " -->"; print_space();
|
|
print_value !toplevel_env res t2; close_box(); print_newline();
|
|
trace_res res
|
|
with exn ->
|
|
open_hovbox 2;
|
|
Printtyp.longident name; print_string " raises"; print_space();
|
|
print_exception (Obj.repr exn); close_box(); print_newline();
|
|
raise exn))
|
|
| _ ->
|
|
(fun v -> v)
|
|
|
|
(* Given the address of a closure, find its instrumented version
|
|
and call it *)
|
|
|
|
let rec find_traced_closure clos = function
|
|
[] ->
|
|
fatal_error "Trace.find_traced_closure"
|
|
| f :: rem ->
|
|
if f.closure == clos then f else find_traced_closure clos rem
|
|
|
|
let print_trace clos arg =
|
|
(Obj.magic
|
|
(find_traced_closure clos !traced_functions).instrumented_fun :
|
|
Obj.t -> Obj.t)
|
|
arg
|
|
|