123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384(**************************************************************************)(* *)(* 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'at='alazy_texceptionUndefinedletraise_undefined=Obj.repr(fun()->raiseUndefined)externalmake_forward:Obj.t->Obj.t->unit="caml_obj_make_forward"(* Assume [blk] is a block with tag lazy *)letforce_lazy_block(blk:'arglazy_t)=letclosure=(Obj.obj(Obj.field(Obj.reprblk)0):unit->'arg)inObj.set_field(Obj.reprblk)0raise_undefined;tryletresult=closure()inmake_forward(Obj.reprblk)(Obj.reprresult);resultwithe->letraise_e=Obj.repr(fun()->raisee)in(* The allocation of [raise_e] below can result in
concurrent/asynchronous code execution, and modify [blk]
itself. We protect against this scenario by checking that the
[set_field] below only happens on [Lazy_tag] blocks, to
preserve type-safety. *)lettag=Obj.tag(Obj.reprblk)iniftag<>Obj.lazy_tagthen(* #13434: at this point we believe that [e] must be
[Undefined], but the reasoning is rather delicate. *)raiseUndefined;Obj.set_field(Obj.reprblk)0raise_e;raisee(* Assume [blk] is a block with tag lazy *)letforce_val_lazy_block(blk:'arglazy_t)=letclosure=(Obj.obj(Obj.field(Obj.reprblk)0):unit->'arg)inObj.set_field(Obj.reprblk)0raise_undefined;letresult=closure()inmake_forward(Obj.reprblk)(Obj.reprresult);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. *)letforce(lzv:'arglazy_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) *)letlzv=Sys.opaque_identitylzvinletx=Obj.reprlzvinlett=Obj.tagxinift=Obj.forward_tagthen(Obj.obj(Obj.fieldx0):'arg)elseift<>Obj.lazy_tagthen(Obj.objx:'arg)elseforce_lazy_blocklzvletforce_val(lzv:'arglazy_t)=letx=Obj.reprlzvinlett=Obj.tagxinift=Obj.forward_tagthen(Obj.obj(Obj.fieldx0):'arg)elseift<>Obj.lazy_tagthen(Obj.objx:'arg)elseforce_val_lazy_blocklzv