Unusual techniques in HLVM and
"Jon Harrop" <[email protected]> Sun, 1 Apr 2012 20:19:13 +0100
| Newsgroups | gmane.comp.programming.garbage-collection.general |
|---|---|
| Message-ID | <[email protected]> |
I just wrote a blog post detailing some of the techniques I adopted in = HLVM that appear to be unusual: http://flyingfrogblog.blogspot.co.uk/2012/03/gc-safe-points-mutator-suspe= nsi on-and.html In particular, HLVM uses many techniques that are much simpler than = existing alternatives but appear to be just as efficient. In the process of writing that I thought of an interesting way to avoid unnecessary pushes to the shadow stack. A previous benchmark indicated = that shadow stack manipulations can account for up to 70% of the total = running time of a program: http://flyingfrogblog.blogspot.co.uk/2009/03/current-shadow-stack-overhea= ds- in-hlvm.html So this theoretically has the potential to dramatically improve HLVM's performance under certain circumstances (although I don't want to = exaggerate the potential advantages because HLVM's current GC is poorly suited for allocation-intensive programs like that benchmark). I wanted to avoid both caller and callee pushing the same value onto the shadow stack. Obviously, there is no harm in just having the caller = push. I thought of an interesting solution: add the ability to mark a reference = type as "prepushed" and instantiate functions for any combination of = prepushed reference arguments as required by callers. This is a conservative approximation so references default to non-prepushed. Between the push = and pop of a reference inside the body of a function it becomes prepushed = and, therefore, any callees receive a prepushed reference. Now, an interesting development of this would be to mark all references derived from prepushed references via immutable types as also being prepushed. For example, consider the idiomatic non-tail recursive fold = right function over immutable singly-linked lists (OCaml/F# code): let rec foldr f xs a =3D match xs with | x::xs -> f x (foldr f xs a) | [] -> [] The initial call to this recursive function will push the head of the = list onto the stack. As the list is immutable we know that the GC will find = the entire list to be reachable for the entire duration of all recursive = calls. A na=EFve solution would push references to every single node in the = list onto the stack but this new solution would only push the head of the list = because all of the other references are derived from the original via values of immutable types. If the fold is accumulating an O(1) size value (e.g. a = sum) then most of the time is probably spent pushing references to list nodes = and pushing return addresses. If the VM "unrolls" the recursive calls as = HLVM does then pushes of return addresses are amortized and most of the time = is spent pushing reference to list nodes, in which case this optimization = might dramatically improve performance. --=20 Dr Jon Harrop, Flying Frog Consultancy Ltd. http://www.ffconsultancy.com