On 2/13/13 10:06 PM, Boris Zbarsky wrote:
That sounds like it should be fast enough, yes.  We should verify that
it actually is in practice.  Which to me suggests that the scheduler
rewrite is a higher priority than, say, floats.  At least if they're
both gated on brson.  ;)  Do we have any ETA on the scheduler rewrite?

Currently, floats aren't really on our priority list; we want them to be done, but other things are higher priority. For example, the scheduler rewrite. :)

The current status of the rewrite is that the scheduler thread (which is the I/O thread in the new design) is starting up tasks, but communication and I/O does not work. I/O is important to get right, since a major impetus for the creation of the new scheduler is to avoid having separate event loops for I/O and scheduling. The two event loops proved to be a big performance problem for I/O (see the threads on rust-dev if you're curious).

I plan to write up my thoughts more on the wiki tomorrow, but I am
currently leaning toward not using copy-on-write and instead just having
the DOM objects' contents be immutable while layout is running.

Hmm.  This loses us a lot of the "quickly return to the event loop and
page script" benefit we're ideally aiming for, I think.  It also makes
doing any sort of speculative layout much more problematic, right?
>
Why the change of heart here?  Or should I just wait for your writeup on
the wiki which will cover that?

So as I write this I realize there is a hybrid solution (#3 below) that we could possibly employ.

The current/old COW scheme uses "handles". In this scheme, if script modifies a DOM object while layout is running, the memory looks like this:

    [ JSObject ] -> [ Handle ]
                    /        \
        [ Script Object ] [ Layout Object ]

This has the problem that there are two allocations (one for the handle) and two levels of indirection for each property access. Moreover, these costs are paid even in the sequential case, when layout is not running:

    [ JSObject ] -> [ Handle ]
                      \    /
                  [ DOM Object ]

Compare this to Gecko/WebKit, where the memory simply looks like this:

    [ JSObject ] -> [ DOM Object ]

In Gecko/WebKit we have just one allocation and one level of indirection. So ideally we would like Servo to have this property as well. The obvious problem is what to do when script modifies the DOM while layout is running. There are a number of strategies we can choose:

(1) Have script block on layout whenever it tries to modify the DOM while layout is running. While it's blocking try to do *something* useful like GC. This can cause jank, however.

(2) Have script append its modification to a journal if layout is running. (If layout is not running, the change is committed directly.) Script then checks the log when doing a get if layout is running. When layout completes, commit all the actions in the journal to the DOM. The advantage to this is that sets while layout is running are very fast (just add to a buffer). The disadvantage is that gets are slow, unless we do something really fancy. (There is an interesting analogy to log structured filesystems and databases here.)

(3) Have script copy the DOM node and store a pointer to the new node in the header of the DOM object.

                     Layout Object           Script Object

                    +-------------------+    +-----------+
    [ JSObject ] -> | Script Object Ptr | -> | fields... |
                    +-------------------+    \/\/\/\/\/\/\
                    | fields...         |
                    \/\/\/\/\/\/\/\/\/\/\

Whenever script does a get, if layout is running, it follows the script object pointer to find the object it should be looking at. When script does a set, it copies the DOM node, sets the script object pointer, and then modifies the copy. Layout never looks at the script object pointer. When layout completes, the layout objects are discarded and the script objects become the new layout objects. This has the advantage that gets are fast; the only overhead is one extra load (to follow the script object pointer). The disadvantage is that sets are slow, because they involve copying the DOM node and allocation.

I am leaning toward (3) now.

I think we should just ignore the fact that Rust cannot currently
inherit traits from structs for now

OK.  How temporary is "for now"?

Niko and I have a proposal and we can bring it up at the next Rust meeting on Tuesday.

and implement the DOM object methods
that have to be virtual using unsafe Rust code.

You mean non-virtual, right?

I mean virtual. Right now virtual in Rust is all-or-nothing; all your methods are virtual or none are. As I understand things, however, the DOM needs a finer-grained approach, in which some methods are virtual, some methods are nonvirtual, and some fields can be accessed at known offsets. So for now we can use structs that Rust already provides, which provide both nonvirtual methods and fields at known offsets out of the box, and then craft vtables out of unsafe code for the DOM methods that absolutely have to be virtual. (Which may be no methods at all, at least for this initial work. You can always simulate simple stuff like tagName with a switch over instanceof self.)

How is this not virtual dispatch?  I feel like I'm missing something,
but I can't tell whether it's my lack of Rust knowledge or something else.

It is virtual dispatch, but it'd be only for the methods that *need* to be virtual. Fields like "firstChild", as well as methods like appendChild(), would be nonvirtual under this scheme.

The endgame I would like to see for our DOM representation is that the
DOM impl can write some sort of (presumably very simple) firstChild
getter in safe Rust code and the binding can be generated in such a way
that the compiler will inline the getter into the binding when all is
said and done.

I see no obstacles to doing this.

That seems ok for basic performance sanity testing, sure.  Not so great
for actual implementation.

Right.

Do we have any ETA on inheritance of traits from structs?  This also
seems like a higher priority than floats.

I don't have one at the moment, but I'll bring it up at the meeting, as I mentioned. I don't *think* it will be hard to implement at least the parts we'll need in Rust, but the trait code is some of the hairiest parts of the compiler, so there might be something unforeseen that would come up. Might be doable in a day or two though. We'll see.

This, too seems like a higher priority than floats.  ;)

We're treating it as such.

Patrick

_______________________________________________
dev-servo mailing list
dev-servo@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-servo

Reply via email to