Re: [dev-servo] Removing shared boxes from the DOM

2013-12-06 Thread Patrick Walton

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

2013-12-06 Thread Niko Matsakis
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

2013-12-06 Thread Niko Matsakis
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

2013-12-06 Thread Patrick Walton
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

2013-12-06 Thread Boris Zbarsky

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

2013-12-06 Thread Niko Matsakis
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