-
Notifications
You must be signed in to change notification settings - Fork 4
/
value.ml
307 lines (277 loc) · 8.6 KB
/
value.ml
1
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
open Printf
type t = Obj.t
let compare = compare
let equal = (==)
let hash = Hashtbl.hash
type tag =
| Lazy
| Closure
| Object
| Infix
| Forward
| Block
| Abstract
| String
| Double
| Double_array
| Custom
| Int
| Out_of_heap
| Unaligned
type custom =
| Custom_nativeint of nativeint
| Custom_int32 of int32
| Custom_int64 of int64
| Custom_bigarray
| Custom_channel
| Custom_unknown
| Not_custom
external bits : t -> nativeint = "inspect_bits"
let hex_digits = "0123456789ABCDEF"
let dec_of_bits v =
sprintf "%nd" v
let hex_of_bits v =
let (lsr) = Nativeint.shift_right in
let (land) = Nativeint.logand in
let ndig = Nativeint.size / 4 in
let b = Buffer.create (2 + ndig + 1) in
Buffer.add_string b "0x";
for i = ndig - 1 downto 0 do
let d = (v lsr (i * 4)) land 0xFn in
Buffer.add_char b hex_digits.[Nativeint.to_int d]
done;
Buffer.contents b
let bin_of_bits v =
let (lsr) = Nativeint.shift_right in
let (land) = Nativeint.logand in
let ndig = Nativeint.size in
let b = Buffer.create (2 + ndig + 1) in
(* three seems reasonable, prefix and maybe null? *)
Buffer.add_string b "0b";
for i = Sys.word_size - 1 downto 0 do
let d = (v lsr i) land 1n in
Buffer.add_string b (if d = 1n then "1" else "0")
done;
Buffer.contents b
let bits_to_string ?(base=`Hex) v =
let bs = bits v in
match base with
| `Dec -> dec_of_bits bs
| `Hex -> hex_of_bits bs
| `Bin -> bin_of_bits bs
external custom_identifier : t -> string = "inspect_custom_id"
external custom_has_finalize : t -> bool = "inspect_custom_has_finalize"
external custom_has_compare : t -> bool = "inspect_custom_has_compare"
external custom_has_hash : t -> bool = "inspect_custom_has_hash"
external custom_has_serialize : t -> bool = "inspect_custom_has_serialize"
external custom_has_deserialize : t -> bool = "inspect_custom_has_deserialize"
let custom_ops_info r =
sprintf "%c%c%c%c%c"
(if custom_has_finalize r then 'F' else '-')
(if custom_has_compare r then 'C' else '-')
(if custom_has_hash r then 'H' else '-')
(if custom_has_serialize r then 'S' else '-')
(if custom_has_deserialize r then 'D' else '-')
let nativeint_id = "_n"
let int32_id = "_i"
let int64_id = "_j"
let bigarray_id = "_bigarray"
let channel_id = "_chan"
module TagSet =
struct
include Set.Make(struct type t = tag let compare = compare end)
let of_list tlist =
List.fold_left (fun s t -> add t s) empty tlist
let all =
of_list [
Lazy;
Closure;
Object;
Infix;
Forward;
Block;
Abstract;
String;
Double;
Double_array;
Custom;
Int;
Out_of_heap;
Unaligned;
]
end
(* Make sure the known custom identifiers are in sync. *)
let _ =
let rnat = Obj.repr 0n and ri32 = Obj.repr 0l and ri64 = Obj.repr 0L in
assert (Obj.tag rnat = Obj.custom_tag);
assert (Obj.tag ri32 = Obj.custom_tag);
assert (Obj.tag ri64 = Obj.custom_tag);
assert (nativeint_id = custom_identifier rnat);
assert (int32_id = custom_identifier ri32);
assert (int64_id = custom_identifier ri64);
(* assert (bigarray_id = custom_identifier ...); *)
assert (channel_id = custom_identifier (Obj.repr stdout));
()
let custom_value r =
if Obj.tag r = Obj.custom_tag then (
let id = custom_identifier r in
if id = nativeint_id then
Custom_nativeint (Obj.magic r : nativeint)
else if id = int32_id then
Custom_int32 (Obj.magic r : int32)
else if id = int64_id then
Custom_int64 (Obj.magic r : int64)
else if id = channel_id then
Custom_channel
else if id = bigarray_id then
Custom_bigarray
else
Custom_unknown
)
else
Not_custom
let custom_is_int r =
match custom_value r with
| Custom_nativeint _ -> false
| Custom_int32 _ -> true
| Custom_int64 _ -> true
| _ -> false
(* Matching an integer value should be faster than a series of if
statements.
That's why all these assertions are here, to make sure
that the integer literals used in the match statement actually
correspond to the tags defined by the Obj module. *)
let _ =
assert (Obj.lazy_tag = 246);
assert (Obj.closure_tag = 247);
assert (Obj.object_tag = 248);
assert (Obj.infix_tag = 249);
assert (Obj.forward_tag = 250);
assert (Obj.no_scan_tag = 251);
assert (Obj.abstract_tag = 251);
assert (Obj.string_tag = 252);
assert (Obj.double_tag = 253);
assert (Obj.double_array_tag = 254);
assert (Obj.custom_tag = 255);
assert (Obj.int_tag = 1000);
assert (Obj.out_of_heap_tag = 1001);
assert (Obj.unaligned_tag = 1002);
()
(* Slower and safer.
let value_tag r =
match tag r with
| x when x = lazy_tag -> Lazy
| x when x = closure_tag -> Closure
| x when x = object_tag -> Object
| x when x = infix_tag -> Infix
| x when x = forward_tag -> Forward
| x when x < no_scan_tag -> Block
| x when x = abstract_tag -> Abstract
| x when x = string_tag -> String
| x when x = double_tag -> Double
| x when x = double_array_tag -> Double_array
| x when x = custom_tag -> Custom
| x when x = int_tag -> Int
| x when x = out_of_heap_tag -> Out_of_heap
| x when x = unaligned_tag -> Unaligned
| x -> failwith (sprintf "OCaml value with unknown tag = %d" x)
*)
(* Faster but more dangerous *)
let tag r =
match Obj.tag r with
| x when x < 246 -> Block
| 246 -> Lazy
| 247 -> Closure
| 248 -> Object
| 249 -> Infix
| 250 -> Forward
| 251 -> Abstract
| 252 -> String
| 253 -> Double
| 254 -> Double_array
| 255 -> Custom
| 1000 -> Int
| 1001 -> Out_of_heap
| 1002 -> Unaligned
| x -> failwith (sprintf "OCaml value with unknown tag = %d" x)
(* Slower? and safer
let is_in_heap r =
let x = Obj.tag r in
not (x = Obj.int_tag || x = Obj.out_of_heap_tag || x = Obj.unaligned_tag)
*)
(* Faster but more dangerous *)
let is_in_heap r =
let x = Obj.tag r in
x < 1000 || 1002 < x
let heap_words r =
if is_in_heap r then Obj.size r else 0
let mnemonic r =
match tag r with
| Lazy -> "LAZY"
| Closure -> "CLOS"
| Object -> "OBJ"
| Infix -> "INFX"
| Forward -> "FWD"
| Block -> "BLK"
| Abstract -> "ABST"
| String -> "STR"
| Double -> "DBL"
| Double_array -> "DBLA"
| Custom -> "CUST"
| Int -> "INT"
| Out_of_heap -> "OADR"
| Unaligned -> "UADR"
let mnemonic_unknown =
"????"
let abbrev r =
match tag r with
| Lazy
| Closure
| Object
| Infix
| Forward
| Block
| Double_array
| String
| Abstract -> sprintf "%s#%d" (mnemonic r) (heap_words r)
| Double -> sprintf "%g" (Obj.magic r : float)
| Custom -> (
match custom_value r with
| Custom_nativeint n -> sprintf "%ndn" n
| Custom_int32 i -> sprintf "%ldl" i
| Custom_int64 i -> sprintf "%LdL" i
| Custom_bigarray -> "Bigarray"
| Custom_channel -> "Channel"
| Custom_unknown -> sprintf "%S %s" (custom_identifier r) (custom_ops_info r)
| Not_custom -> failwith "Value.description: should be a custom value"
)
| Int -> string_of_int (Obj.magic r : int)
| Out_of_heap -> sprintf "0x%nX" (bits r)
| Unaligned -> sprintf "0x%nX" (bits r)
let description r =
match tag r with
| Lazy -> "Lazy: #" ^ string_of_int (Obj.size r)
| Closure -> "Closure: #" ^ string_of_int (Obj.size r)
| Object -> "Object: #" ^ string_of_int (Obj.size r)
| Infix -> "Infix: #" ^ string_of_int (Obj.size r)
| Forward -> "Forward: #" ^ string_of_int (Obj.size r)
| Block -> sprintf "Block(%d): #%d" (Obj.tag r) (Obj.size r)
| Abstract -> "Abstract: #" ^ string_of_int (Obj.size r)
| String ->
let len = String.length (Obj.magic r : string) in
sprintf "String: %d char%s" len (if len > 1 then "s" else "")
| Double -> sprintf "Double: %g" (Obj.magic r : float)
| Double_array -> sprintf "Double_array: %d floats" (Array.length (Obj.magic r : float array))
| Custom -> (
match custom_value r with
| Custom_nativeint n -> sprintf "Nativeint: %nd" n
| Custom_int32 i -> sprintf "Int32: %ld" i
| Custom_int64 i -> sprintf "Int64: %Ld" i
| Custom_bigarray -> "Bigarray"
| Custom_channel -> "Channel"
| Custom_unknown -> sprintf "Custom: %S %s" (custom_identifier r) (custom_ops_info r)
| Not_custom -> failwith "Value.description: should be a custom value"
)
| Int -> sprintf "Int: %d" (Obj.magic r : int)
| Out_of_heap -> sprintf "Out_of_heap (0x%nX)" (bits r)
| Unaligned -> sprintf "Unaligned (0x%nX)" (bits r)