[MLton-commit] r5872

Vesa Karvonen vesak at mlton.org
Tue Aug 14 04:47:16 PDT 2007


Delay HashMap update after rd/wr when dealing with acyclic references.

As noted by Elsman [http://mlton.org/References#Elsman04], Standard ML
does not provide a means of extracting a hashable identity from a mutable
object.  Regardless of identity, structurally equivalent mutable objects
hash to the same value.  This increases the asymptotic complexity of
algorithms, including pickling, that need to distinguish mutable objects
by identity.  Elsman then described two optimized combinators for pickling
references whose use presents additional proof obligations to programmers.
One of the optimized combinators, ref0, simply assumes that no cycles
appear through references pickled with it.  Perhaps surprisingly, it is
possible to perform a similar optimization automatically.  Specifically,
during type representation construction, it is possible to compute a
conservative approximation as to whether values of a mutable type may be a
part of a cycle or not.  An algorithm for this boils down to tracking down
whether a value of the given mutable type may contain values of
(exceptions or) recursive datatypes that may contain a value of the
mutable type.  Our library includes the DataRecInfo generic, which
implements such an algorithm.

----------------------------------------------------------------------

U   mltonlib/trunk/com/ssh/generic/unstable/detail/value/pickle.sml

----------------------------------------------------------------------

Modified: mltonlib/trunk/com/ssh/generic/unstable/detail/value/pickle.sml
===================================================================
--- mltonlib/trunk/com/ssh/generic/unstable/detail/value/pickle.sml	2007-08-14 08:18:30 UTC (rev 5871)
+++ mltonlib/trunk/com/ssh/generic/unstable/detail/value/pickle.sml	2007-08-14 11:47:16 UTC (rev 5872)
@@ -212,16 +212,21 @@
 
    val int as INT {rd=rdInt, wr=wrInt} = bits Word.ops (swap Word.isoIntX)
 
-   fun mutable {readProxy, readBody, writeWhole, hash} = let
+   fun mutable {readProxy, readBody, writeWhole, self} = let
+      val cyclic = Arg.mayBeCyclic self
       val tagD = #"\000" and tagR = #"\001"
-      val (toDyn, fromDyn) = Dyn.new {eq = op =, hash = hash}
+      val (toDyn, fromDyn) = Dyn.new {eq = op =, hash = Arg.hash self}
       open I
       val rd =
           read >>& getState >>= (fn tag & mp =>
           if tag = tagD then
              readProxy >>= (fn proxy =>
-             (HashMap.insert mp (HashMap.numItems mp, toDyn proxy)
-            ; readBody proxy >> return proxy))
+             if cyclic
+             then (HashMap.insert mp (HashMap.numItems mp, toDyn proxy)
+                 ; readBody proxy >> return proxy)
+             else (readBody proxy >>= (fn () =>
+                   (HashMap.insert mp (HashMap.numItems mp, toDyn proxy)
+                  ; return proxy))))
           else if tag = tagR then
              rdInt >>= (fn i =>
              case HashMap.find mp i
@@ -235,12 +240,13 @@
          getState >>= (fn mp =>
          case HashMap.find mp d
           of SOME i => write tagR >> wrInt i
-           | NONE   => let
-                val i = HashMap.numItems mp
-             in
-                HashMap.insert mp (d, i)
-              ; write tagD >> writeWhole v
-             end)
+           | NONE   => 
+                if cyclic
+                then (HashMap.insert mp (d, HashMap.numItems mp)
+                    ; write tagD >> writeWhole v)
+                else write tagD >> writeWhole v >>= (fn () =>
+                     (HashMap.insert mp (d, HashMap.numItems mp)
+                    ; return ())))
       end
    in
       INT {rd = rd, wr = wr}
@@ -345,7 +351,7 @@
           mutable {readProxy = I.thunk (ref o const (Arg.some t)),
                    readBody = fn proxy => I.map (fn v => proxy := v) rd,
                    writeWhole = wr o !,
-                   hash = Arg.hash (Arg.refc ignore t)}
+                   self = Arg.refc ignore t}
       end
 
       fun array t = let
@@ -370,7 +376,7 @@
           mutable {readProxy = I.map (Array.array /> Arg.some t) rdInt,
                    readBody = readBody,
                    writeWhole = writeWhole,
-                   hash = Arg.hash (Arg.array ignore t)}
+                   self = Arg.array ignore t}
       end
 
       fun list t = seq {length = List.length, toSlice = id,
@@ -418,7 +424,7 @@
          end
          fun from s = let
             val buffer = Buffer.new ()
-            fun intToHex i = chr (if i < 10 then i + ord #"0" else i - 10 + ord #"A")
+            fun intToHex i = chr (i + (if i<10 then ord #"0" else ord #"A"-10))
             fun lp s =
                 case Substring.getc s
                  of NONE        => ()




More information about the MLton-commit mailing list