Advertisement
Guest User

Untitled

a guest
Jul 5th, 2015
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.78 KB | None | 0 0
  1. Three GC pointers: `Gc<T>`, `GcRef<'a, T>`, and `GcMove<T>` (aka `GcRoot<T>`). `T: Trace` for all three
  2.  
  3. `GcRef<'a, T>` is really just `&'a Gc<T>` without the extra indirection. Moving on.
  4.  
  5.  
  6. `Gc<T>` is never to be used on the stack. it is only to be used inside struct fields. It implements `Trace`. On the stack, it must be referred to via GcRef or &Gc
  7.  
  8. We abuse the fact that rust doesn't let one move out of a borrow to enforce this. The only thing that is allowed is taking borrows of it.
  9.  
  10. The idea is:
  11.  
  12. - Assume bare Gcs are not allowed on the stack
  13. - Since Gcs are only found in the form of &Gc and GcRef, we can only ever extract an &Gc field out of these because of the no-move-out-of-borrow rule. (Caveat: mem::swap may cause trouble here once we add internal mutability to the mix. I doubt it though). Gc<T> is neither Copy nor Clone, so (&Gc<T>).clone() can't be done.
  14. - So, Gcs not being allowed on the stack is self-consistent; a state with no Gcs on the stack cannot be used to create another state with no Gcs on the stack.
  15. - To top it off, we structure our APIs to never provide bare Gc<T>s.
  16.  
  17.  
  18. This means that Gc<T>s will only live in the great big arena in the sky (well, for now we can just use the regular allocator).
  19.  
  20. However, this provides no way to move out of scope, since we only have borrowed data. For this, the method `.to_move()` will create
  21. a GcMove<T>. This will be opaque (and is NOT `Trace`), but can be moved around freely. It adds a root when constructed, and removes a root when dropped.
  22. It can provide GcRefs. We might want to make it cloneable which will increase the rootcount.
  23.  
  24.  
  25. Of course, this presents us with a small problem. It is now impossible to create Gc<T>s in the first place.
  26.  
  27. Instead of providing APIs that create GC<T>s, we instead provide macros that internally create Gc<T>s and ensure that they are used correctly.
  28.  
  29. For example, if I wish to create a Gc<Foo> from a given Foo, I must use gc!(Foo), which provides me with a GcMove (which can then be converted to a GcRef)
  30.  
  31. On the other hand, if I wish to create a Gc<Foo> where `Foo` itself contains a `Gc<T>`, I use:
  32.  
  33. ```
  34. gc!(
  35. Foo {
  36. .....
  37. thing: Gc::new(...)
  38. }
  39. )
  40. ```
  41.  
  42. The macro will allow the internal Gc::new() to exist, converting it into a hidden function, but will always return a GcMove on the outside.
  43. We can, of course, provide a macro that spits out local GcRefs too.
  44.  
  45. The gc macro will also allow for setting fields on another GC.
  46.  
  47. gc!(
  48. *some_gc_ref.foo.borrow_mut() = another_gc_ref.to_gc()
  49. )
  50.  
  51. `to_gc()` will again be converted to a hidden function that allows for GcRef to be converted into a Gc<T>
  52.  
  53. The advantage here is that tracking roots is simple now; we don't need to worry about leaking roots when a GC goes into the heap.
  54.  
  55. However, this API is much more verbose since the rooting is explicit. Plus macros. Ick.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement