Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
owee_marker.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235type 'result service = .. type _ service += | Name : string service | Traverse : ((Obj.t -> 'acc -> 'acc) -> 'acc -> 'acc) service | Locate : Owee_location.t list service type 'a service_result = | Success of 'a | Unsupported_service | Unmanaged_object let magic_potion = Obj.repr (ref ()) type 'a marker = { magic_potion: Obj.t; service: 'result. 'a -> 'result service -> 'result service_result; } let size_marker = 2 type 'a cycle_marker = { magic_potion: Obj.t; original: 'a marker; unique_id: int; mutable users: int; } let size_cycle_marker = 4 let unique_ids = ref 0 let fresh_name () = incr unique_ids; !unique_ids let make_cycle_marker (marker : _ marker) = { magic_potion; original = marker; unique_id = fresh_name (); users = 0 } let is_marker obj = if Obj.tag obj = 0 && Obj.size obj >= 2 && Obj.field obj 0 == magic_potion then if Obj.size obj = size_marker then `Marker else if Obj.size obj = size_cycle_marker then `Cycle_marker else `No else `No let find_marker t = let rec aux (obj : 'a) i j = if i >= j then `No else let obj' = Obj.field (Obj.repr obj) i in match is_marker obj' with | `Marker -> `Marker (i, (Obj.obj obj' : 'a marker)) | `Cycle_marker -> `Cycle_marker (i, (Obj.obj obj' : 'a cycle_marker)) | `No -> aux obj (i + 1) j in let obj = Obj.repr t in if Obj.tag obj < Obj.lazy_tag then aux t 0 (Obj.size obj) else `No let query_service t service = match find_marker t with | `No -> Unmanaged_object | `Marker (_,marker) | `Cycle_marker (_,{original = marker; _}) -> marker.service t service module type T0 = sig type t val service : t -> 'result service -> 'result service_result end module Unsafe0 (M : T0) : sig val marker : M.t marker end = struct let marker = M.({ magic_potion; service }) end type 'a marked = { cell: 'a; marker: 'a marked marker; } let make_marked cell marker = {cell; marker} let get t = t.cell module Safe0 (M : T0) : sig val mark : M.t -> M.t marked end = struct include Unsafe0(struct type t = M.t marked let service obj (type a) (request : a service) : a service_result = M.service obj.cell request end) let mark cell = make_marked cell marker end (******) module type T1 = sig type 'x t val service : 'x t -> 'result service -> 'result service_result end module Unsafe1 (M : T1) : sig val marker : 'x M.t marker end = struct let marker = M.({ magic_potion; service }) end module Safe1 (M : T1) : sig val mark : 'a M.t -> 'a M.t marked end = struct include Unsafe1(struct type 'a t = 'a M.t marked let service obj (type a) (request : a service) : a service_result = M.service obj.cell request end) let mark cell = make_marked cell marker end module type T2 = sig type ('x, 'y) t val service : ('x, 'y) t -> 'result service -> 'result service_result end module Unsafe2 (M : T2) : sig val marker : ('x, 'y) M.t marker end = struct let marker = M.({ magic_potion; service }) end module Safe2 (M : T2) : sig val mark : ('a, 'b) M.t -> ('a, 'b) M.t marked end = struct include Unsafe2(struct type ('a, 'b) t = ('a, 'b) M.t marked let service obj (type a) (request : a service) : a service_result = M.service obj.cell request end) let mark cell = make_marked cell marker end module type T3 = sig type ('x, 'y, 'z) t val service : ('x, 'y, 'z) t -> 'result service -> 'result service_result end module Unsafe3 (M : T3) : sig val marker : ('x, 'y, 'z) M.t marker end = struct let marker = M.({ magic_potion; service }) end module Safe3 (M : T3) : sig val mark : ('a, 'b, 'c) M.t -> ('a, 'b, 'c) M.t marked end = struct include Unsafe3(struct type ('a, 'b, 'c) t = ('a, 'b, 'c) M.t marked let service obj (type a) (request : a service) : a service_result = M.service obj.cell request end) let mark cell = make_marked cell marker end (* Cycle detection *) type cycle = { (* FIXME: someday, find better than an hashtable, or maybe just drop cycle detection to some library like Phystable? *) seen_ids: (int, unit) Hashtbl.t; (* Cause uncessary retention, switch to weak array?*) mutable seen_objs: Obj.t list; } let seen cycle obj = match find_marker obj with | `No -> `Unmanaged | `Marker _ -> `Not_seen | `Cycle_marker (_,marker) -> if Hashtbl.mem cycle.seen_ids marker.unique_id then `Seen marker.unique_id else `Not_seen let add_to_cycle cycle (obj : 'a) (marker : 'a cycle_marker) = marker.users <- marker.users + 1; Hashtbl.add cycle.seen_ids marker.unique_id (); cycle.seen_objs <- Obj.repr obj :: cycle.seen_objs; `Now_seen marker.unique_id let update_marker (obj : 'a) (field : int) (marker : 'a marker) = Obj.set_field (Obj.repr obj) field (Obj.repr marker) let update_cycle_marker (obj : 'a) (field : int) (marker : 'a cycle_marker) = Obj.set_field (Obj.repr obj) field (Obj.repr marker) let mark_seen cycle obj = match find_marker obj with | `No -> `Unmanaged | `Marker (i,marker) -> let marker = make_cycle_marker marker in update_cycle_marker obj i marker; add_to_cycle cycle obj marker | `Cycle_marker (_,marker) -> if Hashtbl.mem cycle.seen_ids marker.unique_id then `Already_seen marker.unique_id else add_to_cycle cycle obj marker let unmark_seen obj = match find_marker obj with | `Cycle_marker (i,marker) -> marker.users <- marker.users - 1; if marker.users = 0 then update_marker obj i marker.original | `Marker _ -> prerr_endline "UNEXPECTED MARKER"; assert false | `No -> prerr_endline "UNEXPECTED UNMANAGED"; assert false let end_cycle cycle = Hashtbl.reset cycle.seen_ids; let seen_objs = cycle.seen_objs in cycle.seen_objs <- []; List.iter unmark_seen seen_objs let start_cycle () = let cycle = { seen_ids = Hashtbl.create 7; seen_objs = [] } in Gc.finalise end_cycle cycle; cycle