Re: [dev-servo] Removing shared boxes from the DOM
On 12/6/13 10:12 AM, Niko Matsakis wrote: I am not especially happy with these two changes. They feel hokey and special purpose. I guess the best sol'n depends on the degree of static safety we want. Without something like the `'return` lifetime, I'm not sure how we can guarantee that `Root` values follow a stack discipline -- and maybe we don't want to, because it does remove some flexibility (e.g., roots in data structures that transitively are tied to the stack and hence do follow a stack discipline). Wouldn't these data structures be instead traced by the JS GC? ISTM if you are putting roots in a data structure it is best to make the data structure itself traced. I think it's important to have this be safe in an ironclad sense--this is one of the most fundamental pieces of the Servo project--and as a result the `'return` lifetime is the solution I favor right now. Patrick ___ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo
Re: [dev-servo] Removing shared boxes from the DOM
On Thu, Dec 05, 2013 at 09:27:03AM -0800, Patrick Walton wrote: > This is great stuff, thanks. Have you given thought to how the > rooting API would work? That's one of the last major pieces to making > the Servo DOM type- and memory-safe. Just to summarize what you and I talked about on IRC for the record: Last time we talked about this on IRC, it was clear that current Rust could not express the invariants we need to make this safe nor indeed even to conviently implement the mechanism used by C++ today . As I recall we came up with two mechanisms: - some way to extract the return pointer, so that a constructor function knows the address where the return value will be ultimately stored; - a way to prevent values from being moved. The former is an easy hack. The latter is a type system extension that requires a bit of careful thought. The basic idea is to have the borrow checker consider the value "pre-borrowed", since it already prohibits moves from borrowed values. As I call our "rough sketch" of a plan was to say that a function could use the special lifetime `'return` in its return value: struct Root<'a> { ... } fn root() -> Root<'return> { ... } For the callee (`root()`), the `'return` lifetime can be used like other lifetime parameters. For the caller, though, `'return` has special semantics. Precisely what those semantics are is up for debate but here is a simple (though limiting) strawman: the function which employs `'return` must be stored into a local variable, and `'return` is bound to the enclosing block's lifetime. The variable is considered immobile by the borrow check. (This same mechanism could be useful for arenas.) I am not especially happy with these two changes. They feel hokey and special purpose. I guess the best sol'n depends on the degree of static safety we want. Without something like the `'return` lifetime, I'm not sure how we can guarantee that `Root` values follow a stack discipline -- and maybe we don't want to, because it does remove some flexibility (e.g., roots in data structures that transitively are tied to the stack and hence do follow a stack discipline). I was considering the idea of out-pointers a la Go. It would avoid the hokey "get the return slot" thing and also add power to users by putting DPS under their control. But it has complicated interactions with generic functions (I can go into detail on that in a later mail), and moreover it doesn't address the problem of forcing data to live on stack or at least follow a stack discipline. Niko ___ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo
Re: [dev-servo] Removing shared boxes from the DOM
On Fri, Dec 06, 2013 at 10:17:40AM -0800, Patrick Walton wrote: > Wouldn't these data structures be instead traced by the JS GC? ISTM > if you are putting roots in a data structure it is best to make the > data structure itself traced. This is not necessarily the case -- creating a new kind of GCThing is rather hard, and wrapping in an object is heavyweight compared to allocating a data structure on the stack. But thinking about this more, I think that Rust offers some nice solutions here. First off, SpiderMonkey has an AutoObjectVector (I think that's what it's called) that is used to store an arbitrary # of references. I haven't looked at how this is implemented, but I don't see how it could build on the Rooted types, so I guess it's some separate thing. If we can implement Rooted I imagine we can implement this. The only case where Rooted is really workable is when you have a statically known number of things to root (statically known for any given stack frame, at least). A simple example would be a struct with multiple fields: struct Context { a: RootedObject, b: RootedObject } Of course it's probably possible to have the compiler permit something like: let mut x = Context { a: root(), b: root() } even though the return value of `root()` is not being stored directly into an lvalue, but another option would be to use lifetimes: struct Context<'a> { a: &'a mut RootedObject, b: &'a mut RootedObject, } let mut a = root(); let mut b = root(); let mut x = Context { a: &mut a, b: &mut b }; > I think it's important to have this be safe in an ironclad > sense--this is one of the most fundamental pieces of the Servo > project--and as a result the `'return` lifetime is the solution I > favor right now. I tend to agree that we need to get this right and safe. The fact that return has multiple use cases is appealing. However, it's also worth pointing out that once closures are also an ideal solution here, perhaps with some Haskell-do-like sugar to reduce rightward drift. The main problem is the fact that LLVM or the Rust compiler must devirtualize. Niko ___ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo
Re: [dev-servo] Removing shared boxes from the DOM
Devirtualization isn't necessary if we use unboxed closures. Patrick Niko Matsakis wrote: >On Fri, Dec 06, 2013 at 10:17:40AM -0800, Patrick Walton wrote: >> Wouldn't these data structures be instead traced by the JS GC? ISTM >> if you are putting roots in a data structure it is best to make the >> data structure itself traced. > >This is not necessarily the case -- creating a new kind of GCThing is >rather hard, and wrapping in an object is heavyweight compared to >allocating a data structure on the stack. But thinking about this >more, I think that Rust offers some nice solutions here. > >First off, SpiderMonkey has an AutoObjectVector (I think that's what >it's called) that is used to store an arbitrary # of references. I >haven't looked at how this is implemented, but I don't see how it >could build on the Rooted types, so I guess it's some separate >thing. If we can implement Rooted I imagine we can implement this. > >The only case where Rooted is really workable is when you have a >statically known number of things to root (statically known for any >given stack frame, at least). A simple example would be a struct >with multiple fields: > >struct Context { >a: RootedObject, >b: RootedObject >} > >Of course it's probably possible to have the compiler permit >something like: > >let mut x = Context { a: root(), b: root() } > >even though the return value of `root()` is not being stored >directly into an lvalue, but another option would be to use >lifetimes: > >struct Context<'a> { >a: &'a mut RootedObject, >b: &'a mut RootedObject, >} > >let mut a = root(); >let mut b = root(); >let mut x = Context { a: &mut a, b: &mut b }; > >> I think it's important to have this be safe in an ironclad >> sense--this is one of the most fundamental pieces of the Servo >> project--and as a result the `'return` lifetime is the solution I >> favor right now. > >I tend to agree that we need to get this right and safe. The fact that >return has multiple use cases is appealing. However, it's also worth >pointing out that once closures are also an ideal solution here, >perhaps with some Haskell-do-like sugar to reduce rightward drift. The >main problem is the fact that LLVM or the Rust compiler must >devirtualize. > > >Niko -- Sent from my Android phone with K-9 Mail. Please excuse my brevity. ___ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo
Re: [dev-servo] Removing shared boxes from the DOM
On 12/6/13 2:59 PM, Niko Matsakis wrote: This is not necessarily the case -- creating a new kind of GCThing is rather hard, and wrapping in an object is heavyweight compared to allocating a data structure on the stack. Data structures on the stack should be traced with a CustomAutoRooter, in my opinion. That's what Gecko's WebIDL bindings use for dictionaries and sequences and whatnot. At least assuming we can create a CustomAutoRooter subclass with a vtable and the like in Rust... -Boris ___ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo
Re: [dev-servo] Removing shared boxes from the DOM
On Fri, Dec 06, 2013 at 12:51:26PM -0800, Patrick Walton wrote: > Devirtualization isn't necessary if we use unboxed closures. Yes, I was thinking the same thing. Interesting. Niko ___ dev-servo mailing list dev-servo@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-servo