[MLton-devel] Re: finalization in MLton

Matthew Fluet fluet@cs.cornell.edu
Mon, 19 May 2003 08:49:54 -0400 (EDT)


> > Yes.  The implementations are somewhat similar, although I used
> > closures to hide the type of the value while you used exceptions.  One
> > problem I see with your withValue implementation is that it doesn't
> > ensure the finalizer runs after the function completes.
>
> Hmm, I don't think I understand exactly what your point is.  So let me
> state what my intentions for withValue are:
>
>   (1) I don't want to ensure that the finalizer runs after the
>       function completes.  I fact I think that would be wrong becase
>       the finalized value might not be dead at that point.

It isn't that the finalizer gets run when the withValue body completes;
it's that the finalizer gets run after the "last" withValue body
completes.

> Example, let's say tha v is a finalized value:
>
>   withValue (fn x => ...) v
>
> can v be collected in the ... part?  I guess that is what you are
> saying.  Is that because MLton with inline withValue and then realise
> that v can be collected?  If so, how should I "obfuscate" my code so
> that v is protected?

Yes, v can be collected in the ... part.  It doesn't require inlining.
Recall that "v" is really "{value = WRAP x, getVal = fn (WRAP x) => x}",
so the call looks like:

withValue f {value = WRAP x, getVal = fn (WRAP x) => x}
-B->
f ((fn (WRAP x) => x) (WRAP x))
-B->
f x

So, before f even begins to execute, (WRAP x) is no longer live, hence
could be GCed, at which point v's finalizer could be run.  Now, in your
implementation, v's finalizer couldn't be run until Finalized.doGC() was
executed, and if you maintain a discipline that within a withValue
function, you never call Finalized.doGC, then you would be fine -- the
finalizers wouldn't run until f had finished executing.

One thing Steve didn't mention is that the use of finalized values in
MLton installs a "GC handler" to be run after ever GC, which essentially
performs your doGC().  Hence, at any point after the above reduction, a GC
could occur and trigger the finalizers, before f has completed.

>         fun touch v =
>             case v of
>                 Domain => raise Fail "Finalized.touch bug\n"
>               | _      => ()
>
>         fun withValue f (v as {value, getVal}) =
>             wind (fn () => f(getVal value),
> 		  fn () => touch value)
>
> Would this be enough to protect v?  Or is MLton smart enough to
> eliminate the whole touch call, because can v never be the Domain
> exception.

When touch is inlined, then indeed MLton will determine that the Fail
exception cannot be raised.

Really, touch needs to be a compiler primitive.  There's nothing that
prevents MLton from understanding the semantics of reference equality to
optimize

fun touch (r: 'a ref) =
   if r = ref (!r)
      then raise Fail "Finalize.touch bug\n"
   else ()

to

fun touch (r: 'a ref) = ()

and inlining touch, where it would no longer keep the ref cell live.



-------------------------------------------------------
This SF.net email is sponsored by: If flattening out C++ or Java
code to make your application fit in a relational database is painful, 
don't do it! Check out ObjectStore. Now part of Progress Software.
http://www.objectstore.net/sourceforge
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel