Last week was incredibly productive for exact rooting, even if the
counts didn't go down that much.  Once the reviews are done, we'll have
two new tools to help deal with the two major problems we still have
outstanding.

The first new tool is a way to interface to Rooted with non-static
interfaces.  For several months we have been moving to static methods
when we need to exactly root |this|.  This is similar to the wrapper we
added for |Value| on |RootedBase<Value>|.  Unfortunately, for most
|Cell| implementations it is trickier since they want to inline
|Rooted<T>| usage in the header.  Naively, we would need to have the
declaration of |RootedBase<Foo>| in front of |class Foo| (so Rooted<Foo>
is available) and have the forwarders declared afterward.  Obviously,
splitting |RootedBase<Foo>| in half like this is a non-starter.

Luke pointed out that if we pass Foo as a template parameter it gets
resolved lazily -- as a spec matter even and not just as a compiler
detail.  This lets us have our cake and eat it too.  I am going to open
bugs this morning to kill off |self| rooting of |this| and moving
everything over to use this technique.

The second new tool is to deal with this awkward, and extremely common,
compilation failure: |RawFoo foo = js::NewFoo(cx);|.  Ideally, we'd like
to do |.get(nogc);| to unpack the |Return<Foo>| returned by
|js::NewFoo(cx);|  This is impossible because the scope has to contain
the |js::NewFoo(cx)| call, which will GC.  Our other option
is|js::NewFoo(cx).unsafeGet();|, which is both ugly and confusing.  An
even worse option is: |Return<Foo> foo = js::NewFoo(cx);|.  Uhg.

The solution has two parts: first, a lazily-initialized AutoAssertNoGC
analogue called |Raw<T>|; secondly, rewriting |Return<T>| as a
non-lazily-initialized AutoAssertNoGC guard.   We can now do: |RawFoo
foo = js::NewFoo(cx);|  The static type checking guarantees that we do
not try to store the result into an unchecked pointer: it's either Raw
or Rooted unless you do extra work.  The dynamic always-on-in-debug
checking ensures that no GC occurs while the Raw is live.  The
always-on-TBPL rooting analysis catches misuse of naked pointers, if you
have to use them.  In this world, naked pointers get typedefed to
UnsafeFoo, since the only remaining usage of a naked pointer is
explicitly one that is not protected by always-on assertions.

There are some additional nice side-effects from these tools.  One, any
use of |.| to access properties implies that the thing is declared in a
safe way: e.g. use of |->| is a clue at the usage site that you need to
tread carefully when editing.  Two, any function or method that takes a
RawFoo as an argument cannot GC: this allows us to get rid of most of
the explicit AutoAssertNoGC's, keeping the code cleaner while increasing
the assertion coverage.  Lastly, any use of a naked pointer is now
explicitly marked as Unsafe, which is a much more accurate hint than Raw.

-Terrence
_______________________________________________
dev-tech-js-engine-internals mailing list
dev-tech-js-engine-internals@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-js-engine-internals

Reply via email to