|State of Servo||Patrick Walton||6/25/12 3:33 PM|
As requested, here's the state of Servo as it stands.
We have a GitHub repository here: https://github.com/mozilla/servo
Currently what we have builds on Mac and Linux. There's no fundamental
reason why it won't work on Windows, but none of us have put in the
effort necessary to bring it up. The sole platform ("widget" backend in
Gecko terminology) is SDL, but there's an in-process planned move to
GLUT, which should land when the Layers infrastructure is ready. We're
undertaking this move because the Mac port of GLUT is maintained by
Apple and much higher-quality than the Mac SDL port. Neither of these
backends are intended to be long-term solutions; for production we will
want true platform-native backends for each platform.
We make heavy use of Git submodules for modularity--like WebKit, we want
the pieces of Servo to be independently hackable. In addition, we'd like
the components of Servo to be reusable for general Rust apps. For
example, networking, URL parsing, and layers are useful functionality
for a variety of applications, and we can benefit from community
contributions to these components when and if Rust becomes widely used.
Where possible, we reuse existing C and C++ libraries. This doesn't
preclude the possibility of rewriting the functionality provided by
these libraries in safe and parallel Rust code, but it helps us get off
the ground. At the moment, these libraries are:
* HarfBuzz (and its dependency Ragel), for text shaping.
* Azure, for 2D graphics.
* SDL (soon to be replaced with GLUT), as an abstraction layer over the
native windowing system.
* stb_image, for image decoding. This is a very simple image library,
likely insecure and missing support for progressive JPEG, but it's
extremely small and simple, devoid of dependencies, and in the public
* libuv, for networking. This is a library closely associated with
node.js, which abstracts over the asynchronous I/O mechanisms on each
platform. Most notably, it works on Windows, unlike nearly all of the
Our focus so far has been on laying the proper groundwork for a scalable
rendering engine. In particular, we've been focused on decomposing the
rendering pipeline into tasks (lightweight Rust threads), as this is the
part that's most critical to get right and the most difficult to
retrofit onto existing architectures. Right now, Servo has several tasks
in the rendering pipeline. (When we get tab/window support, each of
these tasks will be replicated for each origin.) As I understand it, the
manages layout task lifetimes. DOM structures are shared between this
task and the other tasks in a read-copy-update model; if content
concurrently mutates a DOM node that layout is currently operating on,
that DOM node is copied for the duration of that layout operation.
* A layout task, which supervises layout. Currently, layout is mostly
done sequentially, but our intern Margaret Meyerhoffer has begun to
implement parallel CSS selector matching. Conceptually, the layout task
is one supervisor task with many subtasks to perform parallel layout. At
the moment, this task can perform both toy inline and toy block layout.
* A renderer task, which receives display lists and renders them. When
layers infrastructure lands, there will actually be many renderer tasks,
one for each layer. This will allow us to render layers in parallel.
* A platform task, which manages the main OS thread and native platform
event loop. Nothing happens on this task except for that which
absolutely needs to be handled by it (because the native windowing
library demands it).
* An engine task, which supervises the other tasks and does nothing else.
* An I/O task, which handles networking in an evented, asynchronous
manner via libuv. Note that networking is not yet implemented in Servo,
so this task doesn't do much.
Another major planned task (not yet implemented) is:
* A compositor task, to composite layers together. Scrolling and CSS
animations should be handled by this task as well.
|Re: State of Servo||Robert O'Callahan||6/25/12 4:32 PM|
This all looks pretty good!
FWIW networking and layers aren't actually part of Webkit (URL parsing
didn't used to be either, but they might have fixed that), and anything
near the core engine is quite tangled. I think LLVM is a more impressive
example of modularity.
Sounds reasonable. I think it is important that these libraries get
rewritten in Rust over time, starting with the most Web-facing code ---
Harfbuzz and stb_image. Obviously sorting out the core browser architecture
is higher priority for now, though I'd still like to see a fast JPEG
decoder in Rust to ensure the language can do it.
It seems that right now rcu.rs exposes operations that allow users to do
Note: if the type `T` contains mutable fields, then there is nothing
to stop the reader from
> mutating those fields in the `read()` method. Do not do this. It will lead to race conditions.
> FIXME: We can enforce that this is not done by ensuring that the type `T` contains no mutable
> # Auxiliary data
> Readers can associate a piece of auxiliary data of type `A` along with main nodes. This is
> convenient but dangerous: it is the reader's job to ensure that this data remains live independent
> of the RCU nodes themselves.
Is the FIXME fixable? We'll want to be able to ensure that dom and layout
aren't part of the TCB.
It would be great to be able to run some DOM microbenchmarks to measure RCU
overhead and ensure that single-threaded DOM manipulation is competitive
with existing engines.
I'm glad we're implementing the DOM in Rust. What's the plan for DOM
bindings? That seems to be the most important piece still missing.
I hope we can get someone to start porting Leo's stuff here :-).
Small comment about units: glad to see you using 1/60px appunits, but I
would store them as floats (32bit) --- with fractions not allowed (only an
issue for division or multiplication by a genuine float). Integer overflows
are a large latent problem in existing layout engines.
BTW is the plan still to have integer overflow cause task failure by
default in Rust? I sure hope so! Even assuming we do that, we probably
still want float appunits so that layout can handle extreme coordinates
Also, in Gecko gfx doesn't know about appunits, only layout does. gfx works
in device pixels, usually floats. I'd keep that separation.
“You have heard that it was said, ‘Love your neighbor and hate your enemy.’
But I tell you, love your enemies and pray for those who persecute you,
that you may be children of your Father in heaven. ... If you love those
who love you, what reward will you get? Are not even the tax collectors
doing that? And if you greet only your own people, what are you doing more
than others?" [Matthew 5:43-47]
|Re: State of Servo||Boris Zbarsky||6/25/12 7:02 PM|
On 6/25/12 7:32 PM, Robert O'Callahan wrote:We don't know yet.
In particular, I don't think we've come up with a satisfactory answer to
the ownership model question (aka the "how do we avoid having a cycle
|Re: State of Servo||Robert O'Callahan||6/25/12 7:19 PM|
How about the obvious approach --- have JS and Rust share the same garbage
|Re: State of Servo||Boris Zbarsky||6/25/12 7:31 PM|
On 6/25/12 10:19 PM, Robert O'Callahan wrote:Patrick, how feasible is that? That would certainly solve the problem!
At that point we can do DOM bindings the same way we're doing them in
Gecko now, if desired: codegen them from the WebIDL. We can reuse a all
the parser and data model code, and a lot of the logic (e.g. the
overload resolution implementation) and just have to rejigger the actual
code that gets spit out a bit (like make it not C++).
|Re: State of Servo||Patrick Walton||6/25/12 7:51 PM|
As I understand it, that's the plan. The goal is to have JS and Rust
share the JS heap for all the DOM objects.
Note that this doesn't work for layout data structures, because layout
pose a huge problem, though, because JS has no direct access to those
structures anyway. (It can query the contents of those structures, but
those queries require special handling in any case because in general
query of layout properties requires a reflow.) The tricky part is when
DOM mutations require that layout data structures be discarded (for
example, when nodes are destroyed). The way Niko handles this now is to
have content gather up all those dead layout data structures during JS
object finalization and hand them to layout to be destroyed the next
time layout is triggered. This seems like a reasonable approach; it
keeps sweeping of layout data structures off the content thread, which
is the important thing.
|Re: State of Servo||Patrick Walton||6/25/12 8:01 PM|
On 06/25/2012 04:32 PM, Robert O'Callahan wrote:Ah, interesting. Modularity is one of those things that we need to stay
vigilant about for it to happen. Brian in particular is very keen on
trying to stay modular from the start, and I agree at it's a good goal.
Yes, it should be fixable. Niko and I actually talked about this before
he left for vacation. The easiest way to ensure memory safety is to have
the RCU system actually manage the memory. To eliminate races, we can
use a "const" type bound and the "immutable structures inherit the
mutability of their parent" rule in Rust to make sure there are no races
on the reader side (layout) while ensuring that the writer side
(content) can still write.
In general, we've been trying to innovate using unsafe code in Servo to
figure out what we need, and then folding the ideas back into the Rust
type system to achieve safety.
Agreed. Note that we need the bindings first :)
As mentioned in the other thread, the plan as of now is to have DOM
objects implemented in Rust but to allocate all the DOM objects in the
JS heap (with a fixed memory layout so that we can share pointers
between JS and Rust). DOM methods that don't need to cross layout
boundaries will be implemented as native functions. As Boris mentioned,
we might be able to reuse the bindings generator here.
Yes. It's currently unimplemented, but Michael Sullivan has started to
add support for it because we've already hit overflow issues in vector
OK. As long as you think the performance won't suffer with floating
point ops, I'm happy to move over.
|Re: State of Servo||Jesse Ruderman||6/25/12 8:07 PM|
> Small comment about units: glad to see you using 1/60px appunits, but IWhat's the problem you're trying to solve here? If it's a safety
issue, I'm not sure floats are that much safer. If it's web
compatibility, the rounding issues with a 23-bit mantissa will strike
book-length web pages.
|Re: State of Servo||Boris Zbarsky||6/25/12 8:57 PM|
On 6/25/12 11:01 PM, Patrick Walton wrote:We can do this as long as we get the inter-module APIs right. Which in
practice means as long as we're willing to fix them once we figure out
we got them wrong and keep doing that....
I'm a lot less interested in modularity if it means that we have to have
two separate implementations of HTTP validation/caching like every
single WebKit port has to do, for example.
Hmm. I _could_ try working on a binding generator, I guess. Need to
figure out what it needs to spit out. ;)
So that doesn't quite solve the problem, though it gets us close: we
also need to make sure that various ways to attach sets of JS objects to
DOM objects (primarily addEventListener, but also various other callback
setups) work. We may be able to handle this with just trace class
hooks, I think, as long a we're clear on which DOM object owns what on
the Rust side.
|Re: State of Servo||Robert O'Callahan||6/25/12 9:03 PM|
On Tue, Jun 26, 2012 at 3:07 PM, Jesse Ruderman <jrud...@gmail.com> wrote:I'm not sure either since I haven't built a layout engine using floats, but
In Gecko when an nscoord overflows we can wrap around and end up with
something negative that should never be negative, or otherwise violate
pretty much any invariant involving coordinates. With floats, invariants of
the form "x >= 0 implies y + x >= y and y - x <= y" will always hold (until
you hit NaNs, which are pretty hard to hit from content since most features
don't let you multiply two CSS values). Invariants preconditioned on x > 0
could fail, but I get the feeling those are rare (perhaps because widths
and heights are often zero but never negative).
We would probably still lay out those pages just fine, albeit with reduced
precision on the vertical axis, which doesn't matter much.
|Re: State of Servo||Robert O'Callahan||6/25/12 10:51 PM|
On Tue, Jun 26, 2012 at 10:33 AM, Patrick Walton <pwa...@mozilla.com>wrote:
BTW I think we should try to have separate tasks per browsing context (i.e.
per document). In some cases browsing contexts with the same origin can
communicate and will need to ensure JS observes serial execution, but we
can use messages to achieve that and when JS isn't running we should be
able to run many HTML5 tasks for same-origin documents in parallel.
|Re: State of Servo||Robert O'Callahan||6/25/12 10:55 PM|
On Tue, Jun 26, 2012 at 5:51 PM, Robert O'Callahan <rob...@ocallahan.org>wrote:
I guess that would require using compartments to provide cross-Rust-task
proxies when JS in one document accesses the heap of JS in another
document. Can we do that?
|Re: State of Servo||Boris Zbarsky||6/26/12 8:00 PM|
On 6/26/12 1:51 AM, Robert O'Callahan wrote:Note also that "same-origin" is not invariant for the lifetime of the
document, so I think we'll want various tasks per-compartment anyway
(which is not quite the same as either per-browsing-context or
|Re: State of Servo||Robert O'Callahan||6/26/12 10:56 PM|
On Wed, Jun 27, 2012 at 3:00 PM, Boris Zbarsky <bzba...@mit.edu> wrote:Is this document.domain or more than that? Why can't we have a 1:1
relationship between browsing contexts and compartments?
|Re: State of Servo||Boris Zbarsky||6/27/12 7:01 AM|
On 6/27/12 1:56 AM, Robert O'Callahan wrote:The "same-origin" bit is both document.domain and apparently sandbox CSP
Because a given browsing context can load multiple documents (one after
another), and those can be from different domains. So it has many
compartments corresponding to it. For example, if I have a reference to
a node in a document and the document is unloaded and replaced with
another document, that shouldn't affect whether I can touch the node I
already have a reference to.
|Re: State of Servo||Robert O'Callahan||6/27/12 3:49 PM|
On Thu, Jun 28, 2012 at 2:02 AM, Boris Zbarsky <bzba...@mit.edu> wrote:
>> Is this document.domain or more than that?<iframe sandbox> and CSP can't actually dynamically change the origin of a
document, can they? If they can we'd better fix that before it's too late
Oops, of course. The question then is, can we have a 1:1 relationship
between documents-loaded-in-a-browsing-context (what's the spec name for
that?) and compartments?
|Re: State of Servo||Boris Zbarsky||6/27/12 7:19 PM|
On 6/27/12 6:49 PM, Robert O'Callahan wrote:The proposal to do sandboxing via CSP and the fact that you can put your
CSP into a <meta> tag mean that you can in fact dynamically change the
origin of a document, from whatever origin it had to a null principal,
when said <meta> tag is parsed. Devdatta is implementing that right now...
I do think it's somewhat daft, but people really want to do sandboxing
Not quite, because of silliness with about:blank.
I do think we can have a 1:1 relationship between a Window and a
compartment (and do in Gecko right now).
|Re: State of Servo||bigmikel...@gmail.com||7/2/13 8:31 AM|
So, here's a question nobodies seemed to ask yet: Has anyone decided, exactly, what the user agent string will look like?
Another browser will invariably mean another browser to have to target specifically, in certain cases :)
|Re: State of Servo||Benjamin Smedberg||7/2/13 8:36 AM|
On 7/2/2013 11:31 AM, bigmikel...@gmail.com wrote:No, absolutely not. It's not even worth discussing yet.