-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcamlinternalLazy.ml
73 lines (60 loc) · 3.04 KB
/
camlinternalLazy.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
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Damien Doligez, projet Para, INRIA Rocquencourt *)
(* *)
(* Copyright 1997 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Internals of forcing lazy values. *)
type 'a t = 'a lazy_t
exception Undefined
let raise_undefined = Obj.repr (fun () -> raise Undefined)
external make_forward : Obj.t -> Obj.t -> unit = "caml_obj_make_forward"
(* Assume [blk] is a block with tag lazy *)
let force_lazy_block (blk : 'arg lazy_t) =
let closure = (Obj.obj (Obj.field (Obj.repr blk) 0) : unit -> 'arg) in
Obj.set_field (Obj.repr blk) 0 raise_undefined;
try
let result = closure () in
make_forward (Obj.repr blk) (Obj.repr result);
result
with e ->
Obj.set_field (Obj.repr blk) 0 (Obj.repr (fun () -> raise e));
raise e
(* Assume [blk] is a block with tag lazy *)
let force_val_lazy_block (blk : 'arg lazy_t) =
let closure = (Obj.obj (Obj.field (Obj.repr blk) 0) : unit -> 'arg) in
Obj.set_field (Obj.repr blk) 0 raise_undefined;
let result = closure () in
make_forward (Obj.repr blk) (Obj.repr result);
result
(* [force] is not used, since [Lazy.force] is declared as a primitive
whose code inlines the tag tests of its argument, except when afl
instrumentation is turned on. *)
let force (lzv : 'arg lazy_t) =
(* Using [Sys.opaque_identity] prevents two potential problems:
- If the value is known to have Forward_tag, then its tag could have
changed during GC, so that information must be forgotten (see GPR#713
and issue #7301)
- If the value is known to be immutable, then if the compiler
cannot prove that the last branch is not taken it will issue a
warning 59 (modification of an immutable value) *)
let lzv = Sys.opaque_identity lzv in
let x = Obj.repr lzv in
let t = Obj.tag x in
if t = Obj.forward_tag then (Obj.obj (Obj.field x 0) : 'arg) else
if t <> Obj.lazy_tag then (Obj.obj x : 'arg)
else force_lazy_block lzv
let force_val (lzv : 'arg lazy_t) =
let x = Obj.repr lzv in
let t = Obj.tag x in
if t = Obj.forward_tag then (Obj.obj (Obj.field x 0) : 'arg) else
if t <> Obj.lazy_tag then (Obj.obj x : 'arg)
else force_val_lazy_block lzv