On Thu, Sep 17, 2015 at 6:48 AM, Phil Clayton <[email protected]> wrote:
> 16/09/15 12:40, David Matthews wrote:
>>
>> On 15/09/2015 22:18, Phil Clayton wrote:
>>>
>>> I was wondering how to implement the 'touch' function of
>>> MLTON_FINALIZABLE that forces a weak reference to stay alive.  The
>>> expression
>>>    ignore (PolyML.pointerEq (x, x) orelse raise Fail "touch"; print "");
>>> seems to prevent Poly/ML optimizing the dependence on x away and works
>>> for any type x.  Bizarrely, I found that without print "", the weak
>>> reference stayed alive.  Can you think of something simpler?
>>
>> I looked at the MLton documentation and couldn't understand what "touch"
>> was trying to achieve.  Could you explain it?
>
> "touch t" prevents finalization of t until the call has been evaluated.
> "touch t" an operation that uses t to do nothing, so t cannot be
> garbage-collected until the operation has finished.

Essentially, yes.

"MLton.Finalizable.touch v" is equivalent to
"MLton.Finalizable.withValue (v, fn _ => ())", because "withValue"
guarantees that the finalizers of v will not run before the function
completes.  Of course, internally, both "MLton.Finalizable.touch" and
"MLton.Finalizable.withValue" are implemented using a more primitive
"touch" with the more general type 'a -> unit.  This primitive is
treated by the compiler as an unoptimizable reference to the object;
essentially, it is a future proof method of maintaining a strong
reference to an object and its main use case is to maintain that
strong reference to an object for which there is a weak reference.

For example, suppose one had:

val token = ref ()
val wtoken = Weak.new token
...
val v1 = Weak.get wtoken
...
   !token  (* and no subsequent uses of token *)
...
val v2 = Weak.get wtoken
...

One might expect that v1 is SOME and v2 is NONE.  But, MLton's
optimizations are somewhat tuned towards SML without extensions such
as weak references, so it would be reasonable to replace the "!token"
with "()".  And then v1 could be NONE.  And replacing "!token" with
"token := !token" might be optimized away in a future version of the
compiler.  The "touch" primitive, which perhaps should also be
exported somewhere else in "structure MLton", provides a robust method
instead of the fragile method of crafting a sophisticated nop that
isn't optimized away.  But, thus far, the main use case has been for
finalizers.

>> Is the issue
>> that a global optimising compiler such as MLton could work out that the
>> token was not referenced even though the item was and remove it from the
>> pair at the last reference?
>
> I don't think that is the issue here (as we don't have an item).

In the context of MLton (and now in Poly/ML), the token is a Weak
reference to the item and the check for when to run the finalizers is
whether or not the weak reference has gone NONE.  So, it is something
like the example above that could cause a finalizer to run earlier
than expected if there weren't a touch in each use of the finalized
value.

>> Poly/ML only does that in very limited
>> circumstances.  Is the idea of "touch" that this counts as a reference
>> to the token and that you add a call to it after each reference to the
>> item so that the lifetime of the token is no less than the lifetime of
>> the item?
>
> Yes, but as there is no item, the purpose of touch is to delay finalization
> until some other event has occurred.  One example use of touch is in the
> implementation of Finalizable.finalizeBefore.  The 'other event' is
> finalization of another finalizable value.

Right.  The use case for things like "Finalizable.finalizeBefore" is
when one has a number of C pointers (which to SML look like simple
Word64.word-s), where one knows that it is important to free the
pointed-to C data structures in the right order.  MLton can be a
little more aggressive about "Word64.word ref"s (like flattening them
into a containing data structure), so the "Word64.word ref" and the
Weak reference to it can get a little out of sync as above.  Again, a
"touch" in the right place ensures that the reference is flattened and
the Weak reference properly tracks the object.

-Matthew
_______________________________________________
polyml mailing list
[email protected]
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml

Reply via email to