Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider Ref_alloc and Ref_uninit primitives #209

Open
MatthewFluet opened this issue Oct 23, 2017 · 1 comment
Open

Consider Ref_alloc and Ref_uninit primitives #209

MatthewFluet opened this issue Oct 23, 2017 · 1 comment

Comments

@MatthewFluet
Copy link
Member

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
Copy link
Member Author

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant