mlton icon indicating copy to clipboard operation
mlton copied to clipboard

Consider Ref_alloc and Ref_uninit primitives

Open MatthewFluet opened this issue 7 years ago • 1 comments

It would be possible to extend the ideas from #207 to references. For example, we could have:

structure Unsafe.Ref:
  sig
    val alloc: unit -> 'a ref
    val uninit: 'a ref -> unit
    structure Raw:
      sig
        type 'a rawref
        val alloc: unit -> 'a rawref
        val toRef: 'a rawref -> 'a ref
        val uninit: 'a rawref -> unit
      end
  end

One potential motivation is to eliminate the (admittedly small) dispatch overhead in a ('a -> 'b) ref that is only ever meant to hold one function. For example, recall the classic "back-patching" technique for recursion with first-class functions and references:

val fact_ref = ref (fn _ => raise Fail "fact")
val fact = fn n => if n <= 1 then 1 else n * (!fact_ref) (n - 1)
val () = fact_ref := fact

Control-flow analysis will determine that the contents of fact_ref is either fn _ => raise Fail "fact" or fn n => ..., and the application (!fact_ref) (n - 1) will have a case-analysis to select between these functions. [Note that the overhead is essentially the same, but more obvious to the programmer, when using an ('a -> 'b) option ref.]

With a Ref_alloc primitive, one could write:

val fact_ref = Unsafe.Ref.alloc ()
val fact = fn n => if n <= 1 then 1 else n * (!fact_ref) (n - 1)
val () = fact_ref := fact

Control-flow analysis will determine that the contents of fact_ref is only fn n => ... and the application will have a single (exhaustive) case-match. Subsequent ConstantPropagation and/or Useless optimizations would probably eliminate the reference entirely.

MatthewFluet avatar Oct 23 '17 17:10 MatthewFluet

Another potential use of Ref_alloc and Ref_uninit would be to support Thread_copyCurrent, which currently "returns" the copied thread via GC_getSavedThread, but could be changed to take a thread ref and write the copied thread there. Using Ref_alloc to allocate the thread ref would be convenient, because it is otherwise not easy to obtain a thread to initialize the ref (only to be overwritten).

MatthewFluet avatar Nov 30 '17 14:11 MatthewFluet