The main reason to not do this would be performance (avoiding the
addref/release), but there are two main mitigating factors:
1) All calls to UnwrapReflectorToISupports that pass in a Web IDL object
already do the addref (and in fact QI). So this only affects the
XPCWrappedNative case.
2) The vast majority of the callers proceed to QI on the pointer anyway, and a
second addref is cheap; it's the first addref after a CC that can be
expensive on a cycle-collected object.
Going through the changes one by one:
* In GlobalObject::GetAsSupports, we do have a change that slightly slows down
precisely in the XPCWrappedNative global case. That's the message managers
and the backstagepass. And this really only affects calls to Web IDL statics
from those globals.
* In UnwrapArgImpl we're talking about a Web IDL method taking an "external
interface" type, and the UnwrapReflectorToISupports call is immediately
followed by QI anyway.
* In UnwrapXPConnectImpl we're talking about the case when we have a
non-WebIDL-object implementation of a Web IDL interface. Again, this is the
message manager globals, for EventTarget. And we have a QI call immediately
after the UnwrapReflectorToISupports.
* In the generated HasInstance hook for EventTarget we will be slightly slower
when the LHS of the instanceof is an XPCWrappedNative. And not much slower,
because again there's an immediate QI.
* In InstallXBLField we're never going to have an XPCWrappedNative as thisObj;
it's always an Element in practice. So this is no more expensive than before.
* In sandbox's GetPrincipalOrSOP we now have an extra addref. But it was
followed by various QIs anyway.
* In XPCConvert::JSValToXPCException we have an extra addref if someone throws
an XPCWrappedNative, which is fairly unlikely; our actual Exception objects
are on Web IDL bindings. Plus we have an immediate QI.
* In xpc::HasInstance we have an extra addred if the LHS of instanceof is an
XPCWrappedNative. But, again, there's an immediated QI after the
UnwrapReflectorToISupports.
* In xpcJSWeakReference::Init we are likely doing an extra addref, but again
immediately followed by QI.
I think it's worth making this change just to remove the footgun and that the
perf impact, if any, is pretty minimal.
Most of these changes are just replacements of GetNativeOfWrapper with
UnwrapReflectorToISupports, which is all it did under the hood.
The other changes are as follows:
* In nsDOMClassInfo, we really care whether we have a window, so we can just
UNWRAP_OBJECT to the Window interface, since Window is always on Web IDL
bindings now. Also, the weird compartment check hasn't been needed ever since
GetNativeOfWrapper stopped returning things off the passed-in object's
prototype chain (Firefox 22, bug 658909).
* The only use of do_QueryWrapper was to get a Window in nsDocument; again we
can UNWRAP_OBJECT.
* In XPCJSRuntime, we again just want to check for a Window, so UNWRAP_OBJECT.
The idea is that CastableObjectUnwrapper will want to have a MutableHandle for
the thing it's unwrapping whenever its target is a raw pointer. Since we have
convenient MutableHandle<Value> in most cases, it's easier to switch
CastableObjectUnwrapper to working with MutableHandle<Value> or Handle<Value>
instead of trying to get MutableHandle<JSObject*> in the right places.
There are basically two changes here:
1) Make CastableObjectUnwrapper work with at thing that looks like a Value.
2) Change various callsites to pass in MutableHandle<Value>, in addition to a
Handle<Value>, into the JS-to-C++ conversion templates. The
MutableHandle<Value> is passed as ${maybeMutableVal}. It may not actually
end up being a MutableHandle in some cases.
The reason for passing both a Handle and a MutableHandle is that when the thing
we actually have is a Rooted named "foo" the Handle will be "foo" but the
MutableHandle is most naturally written as "&foo". This is not a problem if
you're just passing it through, but if you want to test whether it's an object,
say, you have a problem. Writing "foo.isObject()" is ok, but "&foo.isObject()"
is not, and neither is "(&foo).isObject()". This could be worked around by
passing the MutableHandle as "JS::MutableHandle<JS::Value>(&foo)" or something,
and then "JS::MutableHandle<JS::Value>(&foo).isObject()" does work. But it
makes the code very hard to read.
So we just pass both things along; ${val} should be used for readonly access and
${maybeMutableVal} any time you really want a MutableHandle.
Thanks to Manish for help in reflecting this idiomatically in rust.
MozReview-Commit-ID: 8tB7vsc5yxc
--HG--
extra : transplant_source : F%87%16%82.P%BD%F3%B1%A4%19%BA%F0%3DQ%F6%ED%BD%95%60
I believe this should fix some incorrect clearing of F_CLASS_FIXED.
MozReview-Commit-ID: 4ga2NEM9M5Z
--HG--
extra : transplant_source : %ECF%CF%D0%F6%19%9F%24%86%EFR%CAVZ%ED%60%D5nU%D8
This gives us performance wins in sevaral areas:
- Creating a structured clone blob of storage data directly from the source
compartment allows us to avoid X-ray and JSON serialization overhead when
storing new values.
- Storing the intermediate StructuredCloneBlob, rather than JSON values,
in-memory saves us additional JSON and structured clone overhead when
passing the values to listeners and API callers, and saves us a fair amount
of memory to boot.
- Serializing storage values before sending them over a message manager allows
us to deserialize them directly into an extension scope on the other side,
saving us a lot of additional structured clone overhead and intermediate
garbage generation.
- Using JSONFile.jsm for storage lets us consolidate multiple storage file
write operations, rather than performing a separate JSON serialization for
each individual storage write.
- Additionally, this paves the way for us to transition to IndexedDB as a
storage backend, with full support for arbitrary structured-clone-compatible
data structures.
MozReview-Commit-ID: JiRE7EFMYxn
--HG--
extra : rebase_source : 04a5681c604c5d2acd781b7ce4f66a757465071a
Currently, we need to be able to handle serializing non-JSON-compatible
objects without catastrophically failing to save the storage file. Ideally, we
would ensure this in the ordinary toJSON method. However, that would require
a unnecessary extra calls to JSON.stringify for each object that needs to be
sanitized before returning a JSON-safe value, which is more expensive than we
can afford.
The fallback toJSONSafe method allows us to do this only when necessary, due
to an initial failed JSON serialization.
MozReview-Commit-ID: JXQ001dOGtW
--HG--
extra : rebase_source : 0b7b388316fdc464b47cdd4f7d8c70bc906a9c27
This is a follow-up to the previous patch, required because on Windows we cannot measure the full height of the main view until it is visible.
MozReview-Commit-ID: 2pfYwMLPYIb
--HG--
extra : rebase_source : 0391a619f551b5e100688ea231d12ac26e0868c8