123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112# 2 "camlinternalLazy.ml"(**************************************************************************)(* *)(* 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. *)(* *)(**************************************************************************)open!Stdlib[@@@ocaml.flambda_o3](* Internals of forcing lazy values. *)[@@@ocaml.afl_inst_ratio0]type'at='alazy_texceptionUndefined(* [update_to_forcing blk] tries to update a [blk] with [lazy_tag] to
[forcing_tag] using compare-and-swap (CAS), taking care to handle concurrent
marking of the header word by a concurrent GC thread. Returns [0] if the
CAS is successful. If the CAS fails, then the tag was observed to be
something other than [lazy_tag] due to a concurrent mutator. In this case,
the function returns [1]. *)externalupdate_to_forcing:Obj.t->int@@portable="caml_lazy_update_to_forcing"[@@noalloc](* [reset_to_lazy blk] expects [blk] to be a lazy object with [Obj.forcing_tag]
and updates the tag to [Obj.lazy_tag], taking care to handle concurrent
marking of this object's header by a concurrent GC thread. *)externalreset_to_lazy:Obj.t->unit@@portable="caml_lazy_reset_to_lazy"[@@noalloc](* [update_to_forward blk] expects [blk] to be a lazy object with
[Obj.forcing_tag] and updates the tag to [Obj.forward_tag], taking care to
handle concurrent marking of this object's header by a concurrent GC thread.
*)externalupdate_to_forward:Obj.t->unit@@portable="caml_lazy_update_to_forward"[@@noalloc](* Assumes [blk] is a block with tag forcing *)letdo_force_blockblk=letb=Obj.reprblkinletclosure=(Obj.obj(Obj.fieldb0):unit->'arg)inObj.set_fieldb0(Obj.repr());(* Release the closure *)tryletresult=closure()inObj.set_fieldb0(Obj.reprresult);update_to_forwardb;resultwithe->Obj.set_fieldb0(Obj.repr(fun()->raisee));reset_to_lazyb;raisee(* Assumes [blk] is a block with tag forcing *)letdo_force_val_blockblk=letb=Obj.reprblkinletclosure=(Obj.obj(Obj.fieldb0):unit->'arg)inObj.set_fieldb0(Obj.repr());(* Release the closure *)letresult=closure()inObj.set_fieldb0(Obj.reprresult);update_to_forwardb;result(* Called by [force_gen] *)letforce_gen_lazy_block~only_val(blk:'arglazy_t)=(* We expect the tag to be [lazy_tag], but may be other tags due to
concurrent forcing of lazy values. *)matchupdate_to_forcing(Obj.reprblk)with|0whenonly_val->do_force_val_blockblk|0->do_force_blockblk|_->raiseUndefined(* used in the %lazy_force primitive *)letforce_lazy_blockblk=force_gen_lazy_block~only_val:falseblk(* [force_gen ~only_val:false] 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_gen~only_val(lzv:'arglazy_t)=(* Using [Sys.opaque_identity] prevents two potential problems:
- If the value is known to have Forward_tag, then it could have been
shortcut during GC, so that information must be forgotten (see GPR#713
and issue #7301). This is not an issue here at the moment since
[Obj.tag] is not simplified by the compiler, and GPR#713 also
ensures that no value will be known to have Forward_tag.
- 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.reprlzvin(* START no safe points. If a GC occurs here, then the object [x] may be
short-circuited, and getting the first field of [x] would get us the wrong
value. Luckily, the compiler does not insert GC safe points at this place,
so it is ok. *)lett=Obj.tagxinift=Obj.forward_tagthen(Obj.obj(Obj.fieldx0):'arg)(* END no safe points *)elseift=Obj.forcing_tagthenraiseUndefinedelseift<>Obj.lazy_tagthen(Obj.objx:'arg)elseforce_gen_lazy_block~only_vallzv