Use of "instanceof SomeDOMInterface" in chrome and extensions

207 views
Skip to first unread message

Boris Zbarsky

unread,
Dec 27, 2012, 5:18:47 AM12/27/12
to
We have a bunch of chrome and extension code that does things like
"instanceof HTMLAnchorElement" (and likewise with other DOM interfaces).

The problem is that per WebIDL spec and general ECMAScript sanity this
shouldn't work: instanceof goes up the proto chain looking for the thing
on the right as a constructor, and chrome's HTMLAnchorElement is not on
the proto chain of web page elements.

The arguably "right" way to do the "el instanceof HTMLAnchorElement"
test is:

el instanceof el.ownerDocument.defaultView.HTMLAnchorElement

Needless to say this sucks.

For now we're violating the spec in a few ways and hacking things like
the above to work, but that involves preserving the nsIDOMHTML*
interfaces, which we'd like to get rid of to reduce memory usage and
whatnot.

So the question is how we should make the above work sanely. I've
brought up the problem a few times on public-script-coord and whatnot,
but there seems to not be much interest in solving it, so I think we
should take the next step and propose a specific solution that we've
already implemented.

One option is to model this on the Array.isArray method ES has. We'd
have to figure out how to name all the methods.

Other ideas?

No matter what we'd then need to migrate our chrome and extensions to
the new setup, so I'd rather not change this more than once. Especially
for extensions.

-Boris

Neil

unread,
Dec 27, 2012, 4:54:18 PM12/27/12
to
Boris Zbarsky wrote:

> We have a bunch of chrome and extension code that does things like
> "instanceof HTMLAnchorElement" (and likewise with other DOM interfaces).

c-c MXR suggests 305 cases of "instanceof HTML.*Element". There are also
18 "instanceof XUL.*Element, 13 "instanceof Element", 14 "instanceof
Node" and 16 "instanceof Document". (A few NodeLists crept in there too,
but they're affected anyway.)

More importantly it suggests 311 for the similar "instanceof
Components.interfaces.nsIDOMHTMLAnchorElement" (or equivalent) often
used in components and modules of course.

So although the 360 or so cases could be changed to e.g.
Node.isNode(obj), that could still potentially exclude a number of
cases. Presumably there's no easy way to avoid the "el instanceof
el.ownerDocument.defaultView.HTMLAnchorElement" from a component?

> the nsIDOMHTML* interfaces, which we'd like to get rid of to reduce
> memory usage and whatnot.

Presumably this involves completely removing all XPIDL DOM interfaces
from HTML nodes, thus saving one vtable entry per node?

--
Warning: May contain traces of nuts.

Justin Dolske

unread,
Dec 27, 2012, 5:49:40 PM12/27/12
to
On 12/27/12 2:18 AM, Boris Zbarsky wrote:

> The arguably "right" way to do the "el instanceof HTMLAnchorElement"
> test is:
>
> el instanceof el.ownerDocument.defaultView.HTMLAnchorElement
>
> Needless to say this sucks.

Eew, indeed.

> So the question is how we should make the above work sanely. [...]
> Other ideas?

Hmm. My first reaction is to gently challenge if this really has to
change, or if it can't be beaten into submission by some other deep
magic hack...

After all, if it's changing a frequently used chrome/addon pattern,
that's a pretty big incompatibility step. And I'd sort of expect an
HTMLAnchorElement to always be an HTMLAnchorElement, without the
creator's context mattering... [1]

But I don't understand the problem space well, so I'll just accept for
the moment that it really really does need to change. :)

One fairly easy (and mechanical?) option would be to add a global helper
function. Something roughly along the lines of:

var isIt = checkForDOMInterface(el, "HTMLAnchorElement");

function checkForDOMInterface(el, kind) {
return (e instanceof el.ownerDocument.defaultView[kind]);
}

That wouldn't be too terrible to do, and is easy to communicate.

A bigger shift might be to change to using existing properties
(.nodeName? .nodeType?) or add something new?

[1] Tangential curiosity on that expectation... What happens today (and
in the future), with something like:

// Hello, I am chrome code adding an anchor to content
var noob = document.createElement("a");
gBrowser.contentDocument.body.appendChild(noob);

// ...later, for an arbitrary node, possibly el === noob
var isAnchor = el instanceof HTMLAnchorElement;

Justin

Neil

unread,
Dec 27, 2012, 6:33:24 PM12/27/12
to
Justin Dolske wrote:

> What happens today (and in the future), with something like:
>
> // Hello, I am chrome code adding an anchor to content
> var noob = document.createElement("a");
> gBrowser.contentDocument.body.appendChild(noob);

If you're lucky, you append a XUL element to the content document. If
you're unlucky, you get a DOM exception. Either way the node isn't an
HTML anchor element.

Justin Dolske

unread,
Dec 28, 2012, 1:45:52 AM12/28/12
to
On 12/27/12 3:33 PM, Neil wrote:

>> What happens today (and in the future), with something like:
>>
>> // Hello, I am chrome code adding an anchor to content
>> var noob = document.createElement("a");
>> gBrowser.contentDocument.body.appendChild(noob);
>
> If you're lucky, you append a XUL element to the content document. If
> you're unlucky, you get a DOM exception. Either way the node isn't an
> HTML anchor element.

Congratulations on missing the point entirely.

Justin

Boris Zbarsky

unread,
Dec 28, 2012, 2:10:29 AM12/28/12
to
On 12/27/12 1:54 PM, Neil wrote:
> More importantly it suggests 311 for the similar "instanceof
> Components.interfaces.nsIDOMHTMLAnchorElement" (or equivalent) often
> used in components and modules of course.

Yeah. We'd obviously need to do something about that...

> Presumably there's no easy way to avoid the "el instanceof
> el.ownerDocument.defaultView.HTMLAnchorElement" from a component?

Since a component has no HTMLAnchorElement hanging off the global, yeah...

> Presumably this involves completely removing all XPIDL DOM interfaces
> from HTML nodes, thus saving one vtable entry per node?

There are cases in which we can remove nsIDOM* stuff without removing
nsIDOMNode/Element/HTMLElement. Which is good, because removing those
is a long-term project.

-Boris

Boris Zbarsky

unread,
Dec 28, 2012, 2:20:34 AM12/28/12
to
On 12/27/12 2:49 PM, Justin Dolske wrote:
> Hmm. My first reaction is to gently challenge if this really has to
> change

Well, it really has to change as exposed to web content (or we have to
convince every single other browser to change behavior and get the
ECMAScript spec changed and so forth).

What happens with chrome is an interesting question we can discuss;
that's what this thread is about.

If really desired, we _could_ make our chrome interface objects behave
differently from content ones and do weird instanceof magic. That would
mean that some edge cases like
Function.prototype.toString.call(HTMLAnchorElement) would do the wrong
thing in chrome (specifically, throw instead of not throwing) and that
you'd have to be very careful about what sort of window you were working
with, but it's pretty doable.

Alternately, we could do something where the proto chain of an Xray for
a content object passes through the corresponding chrome prototypes, not
through Xrays for the content window's prototypes. That would
presumably make "el instanceof
el.ownerDocument.defaultView.HTMLAnchorElement" return false and might
have other issues.

> After all, if it's changing a frequently used chrome/addon pattern,
> that's a pretty big incompatibility step. And I'd sort of expect an
> HTMLAnchorElement to always be an HTMLAnchorElement, without the
> creator's context mattering... [1]

Unfortunately, that's not how instanceof works in JS. Try it with
Object instead of HTMLAnchorElement...

> One fairly easy (and mechanical?) option would be to add a global helper
> function. Something roughly along the lines of:
>
> var isIt = checkForDOMInterface(el, "HTMLAnchorElement");

Right. This would work for elements and for our chrome code. It
doesn't help with the problem on the web, but maybe I should just give
up on solving that as part of the work here. :(

> A bigger shift might be to change to using existing properties
> (.nodeName? .nodeType?) or add something new?

localName and namespaceURI are the relevant things. And they're a bit
of a pain to use, especially namespaceURI. And it's not quite clear to
me how they'll end up interacting with web components.

> // Hello, I am chrome code adding an anchor to content
> var noob = document.createElement("a");
> gBrowser.contentDocument.body.appendChild(noob);
>
> // ...later, for an arbitrary node, possibly el === noob
> var isAnchor = el instanceof HTMLAnchorElement;

Right now on m-c this sets "isAnchor" to true.

If HTMLAnchorElement is switched to follow the spec, it will set
isAnchor to false, because the implicit adoptNode during the appendChild
changes the prototype chain in Gecko.

-Boris

Justin Dolske

unread,
Dec 28, 2012, 3:50:54 AM12/28/12
to
On 12/27/12 11:20 PM, Boris Zbarsky wrote:
> On 12/27/12 2:49 PM, Justin Dolske wrote:
>> Hmm. My first reaction is to gently challenge if this really has to
>> change
>
> Well, it really has to change as exposed to web content (or we have to
> convince every single other browser to change behavior and get the
> ECMAScript spec changed and so forth).

Meaning we're the exception here? How does this impact web content?

>> After all, if it's changing a frequently used chrome/addon pattern,
>> that's a pretty big incompatibility step. And I'd sort of expect an
>> HTMLAnchorElement to always be an HTMLAnchorElement, without the
>> creator's context mattering... [1]
>
> Unfortunately, that's not how instanceof works in JS. Try it with
> Object instead of HTMLAnchorElement...
>[...]
> If HTMLAnchorElement is switched to follow the spec, it will set
> isAnchor to false, because the implicit adoptNode during the appendChild
> changes the prototype chain in Gecko.

Hmm. This is what makes my head hurt a bit. The common case would,
apparently, be wanting to know if someElement is a HTMLFoo or not. Which
seems like it shouldn't matter if it's a Foo in content or a Foo in chrome.

But if Object is already inconsistent here (and unfixable?), maybe it's
just one of those weird "wat" cases of JS that we have to live with?
Seems quite unfortunate, though.

Justin

Neil

unread,
Dec 28, 2012, 6:54:54 AM12/28/12
to
How does removing nsIDOM* stuff without removing nsIDOMNode reduce
memory usage, apart from the slightly reduced size of the QueryInterface
functions themselves, which is a drop in the ocean?

Neil

unread,
Dec 28, 2012, 7:00:07 AM12/28/12
to
Justin Dolske wrote:

> On 12/27/12 3:33 PM, Neil wrote:
>
Congratulations on feeding the troll.

Neil

unread,
Dec 28, 2012, 7:08:41 AM12/28/12
to
Boris Zbarsky wrote:

> Unfortunately, that's not how instanceof works in JS. Try it with
> Object instead of HTMLAnchorElement...

Making foo instanceof Array false across globals was an
extension-breaking change when it happened. Fortunately we have
Array.isArray these days.

Neil

unread,
Dec 28, 2012, 7:12:28 AM12/28/12
to
Neil wrote:

> Boris Zbarsky wrote:
>
>> Unfortunately, that's not how instanceof works in JS. Try it with
>> Object instead of HTMLAnchorElement...
>
> Making foo instanceof Array false across globals was an
> extension-breaking change when it happened. Fortunately we have
> Array.isArray these days.

In the interim I believe foo.constructor.name == "Array" was popular,
but I see that doesn't work for (e.g.) new Image().

Boris Zbarsky

unread,
Dec 28, 2012, 12:15:40 PM12/28/12
to
On 12/28/12 3:54 AM, Neil wrote:
> How does removing nsIDOM* stuff without removing nsIDOMNode reduce
> memory usage

There are elements that implement multiple nsIDOM*, last I checked.

-Boris

Boris Zbarsky

unread,
Dec 28, 2012, 12:18:47 PM12/28/12
to
On 12/28/12 4:12 AM, Neil wrote:
> In the interim I believe foo.constructor.name == "Array" was popular,
> but I see that doesn't work for (e.g.) new Image().

This should work (modulo bugs in exactly the cases where we've hacked
the instanceof behavior) for WebIDL bindings, actually. We could also
make it work for XPConnect DOM constructors....

Sadly, it's not much better than using .ownerDocument.defaultView on the
RHS of instanceof in terms of typing and having to remember to do it.

-Boris

Neil

unread,
Dec 28, 2012, 5:00:46 PM12/28/12
to
But if you're keeping nsIDOMNode, then you might as well keep the most
popular interface that derives from it.

Boris Zbarsky

unread,
Dec 28, 2012, 5:34:35 PM12/28/12
to
On 12/28/12 2:00 PM, Neil wrote:
> But if you're keeping nsIDOMNode, then you might as well keep the most
> popular interface that derives from it.

Probably true, unless we decide we don't care _that_ much about editor
perf and move it to a tearoff....

-Boris

smaug

unread,
Dec 29, 2012, 2:19:36 PM12/29/12
to Boris Zbarsky
On 12/27/2012 12:18 PM, Boris Zbarsky wrote:
> We have a bunch of chrome and extension code that does things like "instanceof HTMLAnchorElement" (and likewise with other DOM interfaces).
>
> The problem is that per WebIDL spec and general ECMAScript sanity this shouldn't work: instanceof goes up the proto chain looking for the thing on the
> right as a constructor, and chrome's HTMLAnchorElement is not on the proto chain of web page elements.
>
> The arguably "right" way to do the "el instanceof HTMLAnchorElement" test is:
>
> el instanceof el.ownerDocument.defaultView.HTMLAnchorElement
>
> Needless to say this sucks.
And doesn't work for data documents which don't have defaultView


>
> For now we're violating the spec in a few ways and hacking things like the above to work, but that involves preserving the nsIDOMHTML* interfaces,
> which we'd like to get rid of to reduce memory usage and whatnot.
>
> So the question is how we should make the above work sanely. I've brought up the problem a few times on public-script-coord and whatnot, but there
> seems to not be much interest in solving it, so I think we should take the next step and propose a specific solution that we've already implemented.
>
> One option is to model this on the Array.isArray method ES has. We'd have to figure out how to name all the methods.

You mean something like Node.is(element, "HTMLAnchorElement"); ?

Robert O'Callahan

unread,
Dec 30, 2012, 5:16:06 PM12/30/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org
On Fri, Dec 28, 2012 at 8:20 PM, Boris Zbarsky <bzba...@mit.edu> wrote:

> Well, it really has to change as exposed to web content (or we have to
> convince every single other browser to change behavior and get the
> ECMAScript spec changed and so forth).
>

How bad would it be to make "<expr> instanceof <expression resolving to
WebIDL interface>" special-cased to re-map the RHS to the appropriate
WebIDL interface object for <expr>?

Rob
--
Jesus called them together and said, “You know that the rulers of the
Gentiles lord it over them, and their high officials exercise authority
over them. Not so with you. Instead, whoever wants to become great among
you must be your servant, and whoever wants to be first must be your
slave — just
as the Son of Man did not come to be served, but to serve, and to give his
life as a ransom for many.” [Matthew 20:25-28]

Andreas Gal

unread,
Dec 30, 2012, 5:23:59 PM12/30/12
to rob...@ocallahan.org, Boris Zbarsky, dev-pl...@lists.mozilla.org

I think it would be extremely surprising to chrome JS authors if instanceof works differently in content and chrome, resulting in very hard to diagnose bugs.

Andreas

On Dec 31, 2012, at 12:16 AM, "Robert O'Callahan" <rob...@ocallahan.org> wrote:

> On Fri, Dec 28, 2012 at 8:20 PM, Boris Zbarsky <bzba...@mit.edu> wrote:
>
>> Well, it really has to change as exposed to web content (or we have to
>> convince every single other browser to change behavior and get the
>> ECMAScript spec changed and so forth).
>>
>
> How bad would it be to make "<expr> instanceof <expression resolving to
> WebIDL interface>" special-cased to re-map the RHS to the appropriate
> WebIDL interface object for <expr>?
>
> Rob
> --
> Jesus called them together and said, “You know that the rulers of the
> Gentiles lord it over them, and their high officials exercise authority
> over them. Not so with you. Instead, whoever wants to become great among
> you must be your servant, and whoever wants to be first must be your
> slave — just
> as the Son of Man did not come to be served, but to serve, and to give his
> life as a ransom for many.” [Matthew 20:25-28]
> _______________________________________________
> dev-platform mailing list
> dev-pl...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform

Robert O'Callahan

unread,
Dec 30, 2012, 5:28:56 PM12/30/12
to Andreas Gal, Boris Zbarsky, dev-pl...@lists.mozilla.org
On Mon, Dec 31, 2012 at 11:23 AM, Andreas Gal <g...@mozilla.com> wrote:

> I think it would be extremely surprising to chrome JS authors if
> instanceof works differently in content and chrome, resulting in very hard
> to diagnose bugs.
>

What if we made it work that way in content as well?

Yes, ultra-dirty and all that, but in terms of least-surprise, stuff like
"iframe.contentDocument.documentElement instanceof Node" being false is
pretty surprising to most authors too.

Neil

unread,
Dec 30, 2012, 7:43:52 PM12/30/12
to
Boris Zbarsky wrote:

> Alternately, we could do something where the proto chain of an Xray
> for a content object passes through the corresponding chrome
> prototypes, not through Xrays for the content window's prototypes.
> That would presumably make "el instanceof
> el.ownerDocument.defaultView.HTMLAnchorElement" return false and might
> have other issues.

I don't think that would work, because you wouldn't expect the Xray for
a content object to have methods that you added to the prototype of the
chrome object. (I would actually expect the proto of an Xray for a
content object to be an [xpconnect wrapped native prototype], but I'm
probably asking too much.)

Bobby Holley

unread,
Dec 30, 2012, 7:50:47 PM12/30/12
to smaug, dev-pl...@lists.mozilla.org
Sorry for taking so long to weigh in here.

There are two main cases to consider.

Content->Content, same-origin (via transparent CrossCompartmentWrappers):
This is the most web-visible area, and thus the one where we should be the
most careful. I don't think we should unilaterally implement any kind of
non-ECMA hacks that the web doesn't already depend on. It would only
further fracture the ecosystem that we're working so hard to mend. If we
think that such behavior would seriously improve the web as a platform, we
should get consensus from other vendors and get Hixie to put an explicit
ECMA deviation in HTML5 (which has been done before).

Chrome->Content, Xray delegation: This is the primary case that Boris was
asking about.

In the long term, I'd like for Xray wrappers to behave more logically with
respect to the prototype chain than they have in the past. I believe that
Peter has already taken the first step by giving us meaningful Xrays to DOM
prototypes and interface objects, but the resolution still happens via the
one-stop-shop resolveNativeProperty (via
XrayWrapper::getPropertyDescriptor) which queries the entire spectrum of
inherited properties directly on then Xray-ed object. I would prefer this
to happen properly via the wrapped prototype chain, so that native
properties on Xrayed objects could be shadowed via expandos on the (Xrayed)
prototype chain. This seems most correct to me, and IMO best captures the
spirit of Xrays: we want the Xrayed objects to behave as normally as
possible, but just be free of any tampering by script associated with their
scope.

So while Boris' suggestion of remapping the prototypes of Xray-ed
prototypes would work (indeed, we've proven it's possible with COWs), I
don't think we should do it. It violates the above-mentioned spirit of
Xrays with very unintuitive behavior, which is likely to lead to the kinds
of inconsistencies that Gal mentioned. In particular, content DOM objects
from multiple scopes would then appear to share prototypes. What's more,
this puts us in a near-impossible position when Xrays are waived (via
.wrappedJSObject or XPCNativeWrapper.unwrap()): do we remap the prototypes
(violating the guarantee of transparency) or not (making the behavior of
waived objects inconsistent with other objects for seemingly arbitrary
reasons)?

Given that, it would appear that we have two options:
(1) Implement a HasInstance hook for Paris Binding interface objects in
chrome scopes only.
(2) Force addons to change.

(2) is always an option, but IMO it should be a pretty high bar. We can
only do so much of that, and I'm not convinced that the compatibility hacks
here will cost of very much. It seems like we could just do (1) with very
little code, by just checking the JSClass. But maybe I'm missing something?

Cheers,
bholley

Boris Zbarsky

unread,
Dec 31, 2012, 1:07:29 AM12/31/12
to
On 12/29/12 11:19 AM, smaug wrote:
> And doesn't work for data documents which don't have defaultView

Hrm... Yes.

> You mean something like Node.is(element, "HTMLAnchorElement"); ?

Or HTMLAnchorElement.isHTMLAnchorElement(element) or
HTMLAnchorElement.is(element) or something....

-Boris

Boris Zbarsky

unread,
Dec 31, 2012, 1:08:34 AM12/31/12
to
On 12/30/12 2:16 PM, Robert O'Callahan wrote:
> How bad would it be to make "<expr> instanceof <expression resolving to
> WebIDL interface>" special-cased to re-map the RHS to the appropriate
> WebIDL interface object for <expr>?

In terms of implementation complexity on our end, it's trivial as long
as we don't follow the WebIDL spec and make things like
HTMLAnchorElement actual Function instances.

In terms of specs and getting other UAs to go along... I don't know.

-Boris

Boris Zbarsky

unread,
Dec 31, 2012, 1:10:26 AM12/31/12
to
On 12/30/12 4:43 PM, Neil wrote:
> (I would actually expect the proto of an Xray for a
> content object to be an [xpconnect wrapped native prototype]

If you expect that for WebIDL objects... you're going to be
disappointed. ;)

-Boris

Boris Zbarsky

unread,
Dec 31, 2012, 1:12:25 AM12/31/12
to
On 12/30/12 4:50 PM, Bobby Holley wrote:
> It seems like we could just do (1) with very
> little code, by just checking the JSClass.

Right now we can even do it simply by delegating to QI (see
hasInstanceInterface annotations in Bindings.conf), but yes, adding code
to check the protoid chain in the JSClass would be very simple.

-Boris

Bobby Holley

unread,
Dec 31, 2012, 1:16:49 AM12/31/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org
Well, you mentioned that one of the costs of maintaining this behavior
would be maintaining the nsIDOMFoo interfaces right? So I'm suggesting that
we use codegen and the JSClass to short-circuit that stuff.

Andreas Gal

unread,
Dec 31, 2012, 1:34:58 AM12/31/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org
In this sea of terrible choices, how about making HTMLAnchorElement an actual function, but having it return "object" for typeof? That should be reasonably Web-compatible.

Andreas

>
> -Boris

Boris Zbarsky

unread,
Dec 31, 2012, 1:44:50 AM12/31/12
to
On 12/30/12 10:34 PM, Andreas Gal wrote:
> In this sea of terrible choices, how about making HTMLAnchorElement an actual function, but having it return "object" for typeof?

Apart from being an ES violation (which we're in the business of anyway,
at the moment), what does that actually buy us?

Right now, in my tree, HTMLAnchorElement is an object with a [[Call]],
so typeof returns "function" and it has a JSClass that lets us override
the behavior of instanceof.

But if it were an actual function then we couldn't change how instanceof
behaves (it would just look up the proto chain of the LHS for the value
of HTMLAnchorElement.prototype), right? What do we get from making its
typeof return "object"?

Feel like I'm missing something,
Boris

Andreas Gal

unread,
Dec 31, 2012, 1:53:53 AM12/31/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org

"In terms of implementation complexity on our end, it's trivial as long as we don't follow the WebIDL spec and make things like HTMLAnchorElement actual Function instances."

You said you want to make it a function. I am just trying to say thats ok, as long it says "object" for typeof.

Andreas

Boris Zbarsky

unread,
Dec 31, 2012, 2:03:25 AM12/31/12
to
On 12/30/12 10:53 PM, Andreas Gal wrote:
>
> "In terms of implementation complexity on our end, it's trivial as long as we don't follow the WebIDL spec and make things like HTMLAnchorElement actual Function instances."
>
> You said you want to make it a function. I am just trying to say thats ok, as long it says "object" for typeof.

Ah, sorry. That was ambiguous. The "as long as we don't" applied to
everything after it. Per WebIDL, interface objects are plain vanilla
functions. In Gecko's WebIDL bindings that's what they are, except in
cases when we need to make instanceof do the non-ECMAScript thing, in
which case we have to make them non-function objects because we need a
custom JSClass with a custom hasInstance hook.

We fake things a bit to make them look sort of like functions, but
they're not actually functions, and that's web-detectable (e.g.
Function.prototype.toString.call(Node) will throw). We could obviously
try to fix things up somehow to make them look completely like functions...

But that sidetracks from the main questions which are:

1) How do we want this to work going forward for chrome touching content?

2) How do we want this to work going forward for web pages touching
other web pages?

3) Can we make #1 and #2 look identical?

3) If #2 doesn't match what WebIDL/ES5 does right now, can we get the
relevant specs and other UAs to align with what we want?

Answers to #1 and especially #2 are what I'm primarily after so far...

-Boris

Bobby Holley

unread,
Dec 31, 2012, 2:14:16 AM12/31/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org
In case anyones' eyes glazed over reading my last post, here's my reduced
2c:

1) How do we want this to work going forward for chrome touching content?
>

|obj instanceof Node| should return true.


> 2) How do we want this to work going forward for web pages touching other
> web pages?
>

|obj instanceof Node| should return false until the standards community
decides something to the contrary and specs it.


> 3) Can we make #1 and #2 look identical?
>

No.


> 3) If #2 doesn't match what WebIDL/ES5 does right now, can we get the
> relevant specs and other UAs to align with what we want?
>

See (2). I'm in favor of Mozilla taking the back seat on this one - I'm
happy to implement it if other vendors are pushing for it, but think we
have bigger things to be pushing for ourselves.

bholley

Neil

unread,
Dec 31, 2012, 9:18:13 AM12/31/12
to
Yeah, well I still wish Xrays had been implemented as completely
distinct wrappers for the underlying C++ object, with
XPCNativeWrapper.unwrap() and wrap() the only links between the two sets
of wrappers. I don't know whether that would have an equivalent in
WebIDL though.

Neil

unread,
Dec 31, 2012, 9:22:20 AM12/31/12
to
Bobby Holley wrote:

>In the long term, I'd like for Xray wrappers to behave more logically with respect to the prototype chain than they have in the past. I believe that Peter has already taken the first step by giving us meaningful Xrays to DOM prototypes and interface objects
>
What does meaningful mean here? I don't think I've ever looked at the
prototype of an Xrayed content node from chrome; I can just about see
the use case of looking at the prototype of a waived node from chrome.

Bobby Holley

unread,
Dec 31, 2012, 12:37:37 PM12/31/12
to Neil, dev-pl...@lists.mozilla.org
Meaningful in this case means that they're not entirely opaque, as was the
case for the traditional [xpconnect wrapped native prototype] XPCWN protos
and constructors. You can do things like "new
contentWindow.XMLHttpRequest", and I believe you can access constants,
properties, and methods.

The goal of Xrays is that waiving should be unnecessary unless you actually
want to see content expandos, so we want them to behave as naturally as
possible.

Anyway, this is getting off-topic for this thread. I'm happy to talk about
it more in another thread or on IRC though. ;-)

Cheers,
bholley

Boris Zbarsky

unread,
Dec 31, 2012, 6:58:27 PM12/31/12
to
On 12/30/12 11:14 PM, Bobby Holley wrote:
> 1) How do we want this to work going forward for chrome touching content?
>
> |obj instanceof Node| should return true.
>
>> 2) How do we want this to work going forward for web pages touching other
>> web pages?
>
> |obj instanceof Node| should return false until the standards community
> decides something to the contrary and specs it.

OK. What do we do with b2g? I'm not quite sure whether the code in
there I see using instanceof is running in "chrome"; most of b2g doesn't
do that....

> See (2). I'm in favor of Mozilla taking the back seat on this one - I'm
> happy to implement it if other vendors are pushing for it, but think we
> have bigger things to be pushing for ourselves.

If we weren't running into this problem head-on ourselves, including in
b2g, I wouldn't be worrying about it as much as I am, yeah. But we are.

-Boris

Bobby Holley

unread,
Dec 31, 2012, 7:26:28 PM12/31/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org
On Mon, Dec 31, 2012 at 3:58 PM, Boris Zbarsky <bzba...@mit.edu> wrote:

> On 12/30/12 11:14 PM, Bobby Holley wrote:
>
>> 1) How do we want this to work going forward for chrome touching content?
>>
>> |obj instanceof Node| should return true.
>>
>> 2) How do we want this to work going forward for web pages touching
>>> other
>>> web pages?
>>>
>>
>> |obj instanceof Node| should return false until the standards community
>> decides something to the contrary and specs it.
>>
>
> OK. What do we do with b2g? I'm not quite sure whether the code in there
> I see using instanceof is running in "chrome"; most of b2g doesn't do
> that....


Well, if we're talking about JS-implemented WebAPIs, then that stuff should
be running as chrome, potentially in the content process (unless I'm
mistaken - I'm still a bit behind on all the b2g architecture). If we're
talking about web apps, then they're supposed to be regular old web
content, and we shouldn't do anything special for them in Gecko. Doing so
undermines our position that these apps are open and portable.

If we think it would significantly improve the web as a platform, I'm
certainly down to push for it (in the front seat) with other vendors. But
I'd think the arguments should be based on improving the HTML5 developer
experience, rather than improving the B2G developer experience.
Theoretically, there isn't supposed to be much of a difference. ;-)

bholley

Boris Zbarsky

unread,
Dec 31, 2012, 7:45:05 PM12/31/12
to
On 12/31/12 4:26 PM, Bobby Holley wrote:
> Well, if we're talking about JS-implemented WebAPIs, then that stuff should
> be running as chrome, potentially in the content process (unless I'm
> mistaken - I'm still a bit behind on all the b2g architecture). If we're
> talking about web apps, then they're supposed to be regular old web
> content, and we shouldn't do anything special for them in Gecko. Doing so
> undermines our position that these apps are open and portable.

We're talking about the b2g UI. And I'm not talking theoretically; it's
using instanceof on HTML elements right now. So either we change that
code, or we make those instanceof checks work or something.

> I'd think the arguments should be based on improving the HTML5 developer
> experience

Yes, of course. As I said, this has come up multiple times in the past,
precisely on those grounds.

-Boris

Bobby Holley

unread,
Dec 31, 2012, 8:08:13 PM12/31/12
to Boris Zbarsky, dev-pl...@lists.mozilla.org
On Mon, Dec 31, 2012 at 4:45 PM, Boris Zbarsky <bzba...@mit.edu> wrote:

> On 12/31/12 4:26 PM, Bobby Holley wrote:
>
>> Well, if we're talking about JS-implemented WebAPIs, then that stuff
>> should
>> be running as chrome, potentially in the content process (unless I'm
>> mistaken - I'm still a bit behind on all the b2g architecture). If we're
>> talking about web apps, then they're supposed to be regular old web
>> content, and we shouldn't do anything special for them in Gecko. Doing so
>> undermines our position that these apps are open and portable.
>>
>
> We're talking about the b2g UI. And I'm not talking theoretically; it's
> using instanceof on HTML elements right now. So either we change that
> code, or we make those instanceof checks work or something.


Gaia? I think we should consider any reliance on this behavior a bug for
now, otherwise the project is standards-based in name only. Gecko is
currently the only engine implementing all the WebAPIs, but we're hoping
that will change. And when it does, it would suck if the apps still didn't
work because they were actually relying on all sorts of non-standard Gecko
junk.

I'd think the arguments should be based on improving the HTML5 developer
> experience
>

Yes, of course. As I said, this has come up multiple times in the past,
> precisely on those grounds.


It also sounds from your initial post that other vendors weren't very
receptive to the idea. If so, that's a shame. Maybe we could try again?
Nevertheless, if they won't listen, I think we should remove our hacks and
align with the spec (fixing any gaia breakage), rather than entrenching our
nonstandard behavior. This can't be an unreasonable requirement to place on
Gaia, since it's also the state of affairs on the open web.

bholley

Robert O'Callahan

unread,
Dec 31, 2012, 8:12:00 PM12/31/12
to Bobby Holley, Boris Zbarsky, dev-pl...@lists.mozilla.org
On Tue, Jan 1, 2013 at 2:08 PM, Bobby Holley <bobby...@gmail.com> wrote:

> It also sounds from your initial post that other vendors weren't very
> receptive to the idea. If so, that's a shame. Maybe we could try again?
>

I interpreted Boris to mean other vendors were apathetic rather than
opposed.

If it was just apathy, then I think we should go for it and make instanceof
magic for WebIDL interface objects in both content and chrome, and try to
get specs and other engines to follow suit.

Bobby Holley

unread,
Dec 31, 2012, 8:26:39 PM12/31/12
to rob...@ocallahan.org, Boris Zbarsky, dev-pl...@lists.mozilla.org
On Mon, Dec 31, 2012 at 5:12 PM, Robert O'Callahan <rob...@ocallahan.org>wrote:

> I interpreted Boris to mean other vendors were apathetic rather than
> opposed.
>
> If it was just apathy, then I think we should go for it and make
> instanceof magic for WebIDL interface objects in both content and chrome,
> and try to get specs and other engines to follow suit.
>

But IIUC the magic already works via XPConnect/nsDOMClassInfo quirks. This
is why Gaia developers are starting to rely on it, and why Boris is
wondering whether he should propagate that magic into WebIDL bindings.

So we've already been implementing this for years, and so continuing to do
it is unlikely to pique the interest of other vendors. Thus, if we can't
solve this at the spec level now, it's unclear to me what else we can do.
And I'm more in favor of aligning with the spec than preserving our
non-standard sugar.

bholley

Robert O'Callahan

unread,
Dec 31, 2012, 11:01:42 PM12/31/12
to Bobby Holley, Boris Zbarsky, dev-pl...@lists.mozilla.org
On Tue, Jan 1, 2013 at 2:26 PM, Bobby Holley <bobby...@gmail.com> wrote:

> But IIUC the magic already works via XPConnect/nsDOMClassInfo quirks. This
> is why Gaia developers are starting to rely on it, and why Boris is
> wondering whether he should propagate that magic into WebIDL bindings.
>
> So we've already been implementing this for years, and so continuing to do
> it is unlikely to pique the interest of other vendors. Thus, if we can't
> solve this at the spec level now, it's unclear to me what else we can do.
> And I'm more in favor of aligning with the spec than preserving our
> non-standard sugar.
>

Yes, that is a good point. I hadn't considered that other browsers already
follow the spec here, so following the spec isn't likely to break Web
content.

Though, if you look at pages like
http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object,
it's sad to see that all the answers are wrong, and the closest-to-correct
answer fails because of the issue at hand.

Boris Zbarsky

unread,
Dec 31, 2012, 11:25:11 PM12/31/12
to
On 12/31/12 5:08 PM, Bobby Holley wrote:
> I think we should consider any reliance on this behavior a bug for
> now

Fine. Then the question becomes: how do we _not_ rely on this behavior?
As smaug pointed out upthread there is actually no sane way to do that
right now.

> It also sounds from your initial post that other vendors weren't very
> receptive to the idea.

They were, as roc points out, apathetic. Or rather, there was some talk
about it being a good idea but no concrete proposals and nothing
actually happening.

> This can't be an unreasonable requirement to place on
> Gaia, since it's also the state of affairs on the open web.

The state of affairs on the open web is totally broken.

-Boris

Boris Zbarsky

unread,
Dec 31, 2012, 11:33:42 PM12/31/12
to
On 12/31/12 8:25 PM, Boris Zbarsky wrote:
> They were, as roc points out, apathetic. Or rather, there was some talk
> about it being a good idea but no concrete proposals and nothing
> actually happening.

That said, I posted one more time on public-script-coord (and bcced
es-discuss) just to see if people bite this time.

-Boris

Robert O'Callahan

unread,
Jan 1, 2013, 2:11:54 AM1/1/13
to Bobby Holley, Boris Zbarsky, dev-pl...@lists.mozilla.org
Another way of looking at the problem: should there be an API to determine
if an object implements a particular WebIDL interface? I hope we agree the
answer is yes... In that case, what would we call it? Can we call it
something that doesn't sound like "instanceOf", and explain with a straight
face why it should be used instead of instanceOf, and expect that authors
will actually use it instead of just using instanceOf?

Jesper Kristensen

unread,
Jan 1, 2013, 7:39:48 AM1/1/13
to
Den 29-12-2012 20:19smaug skrev:
> On 12/27/2012 12:18 PM, Boris Zbarsky wrote:
>> We have a bunch of chrome and extension code that does things like
>> "instanceof HTMLAnchorElement" (and likewise with other DOM interfaces).
>>
>> The problem is that per WebIDL spec and general ECMAScript sanity this
>> shouldn't work: instanceof goes up the proto chain looking for the
>> thing on the
>> right as a constructor, and chrome's HTMLAnchorElement is not on the
>> proto chain of web page elements.
>>
>> The arguably "right" way to do the "el instanceof HTMLAnchorElement"
>> test is:
>>
>> el instanceof el.ownerDocument.defaultView.HTMLAnchorElement
>>
>> Needless to say this sucks.
> And doesn't work for data documents which don't have defaultView

Wouldn't this work? (for chrome code)

el instanceof Components.utils.getGlobalForObject(el).HTMLAnchorElement



Neil

unread,
Jan 1, 2013, 12:51:26 PM1/1/13
to
Bobby Holley wrote:

>You can do things like "new contentWindow.XMLHttpRequest"
>
That's a good example, thanks.

Ehsan Akhgari

unread,
Jan 2, 2013, 2:48:26 PM1/2/13
to Boris Zbarsky, dev-pl...@lists.mozilla.org
On 2012-12-28 5:34 PM, Boris Zbarsky wrote:
> On 12/28/12 2:00 PM, Neil wrote:
>> But if you're keeping nsIDOMNode, then you might as well keep the most
>> popular interface that derives from it.
>
> Probably true, unless we decide we don't care _that_ much about editor
> perf and move it to a tearoff....

We should just fix the editor to not rely on those interfaces. It is
already slow enough as it is. ;-)

Ehsan

Neil

unread,
Jan 3, 2013, 7:06:27 PM1/3/13
to
Bobby Holley wrote:

>In the long term, I'd like for Xray wrappers to behave more logically with respect to the prototype chain than they have in the past.
>
Some nodes, such as HTMLImageElement nodes, expose more properties on
their "Xray" wrappers than on their content wrappers. Does this apply to
the HTMLImageElement prototype itself and its Xray, or do they get
separate prototypes?

Colby Russell

unread,
Aug 17, 2013, 9:04:22 AM8/17/13
to
On 12/28/2012 11:18 AM, Boris Zbarsky wrote:
> On 12/28/12 4:12 AM, Neil wrote:
>> In the interim I believe foo.constructor.name == "Array" was popular,
>> but I see that doesn't work for (e.g.) new Image().
>
> This should work (modulo bugs in exactly the cases where we've hacked
> the instanceof behavior) for WebIDL bindings, actually. We could also
> make it work for XPConnect DOM constructors....
>
> Sadly, it's not much better than using .ownerDocument.defaultView on the
> RHS of instanceof in terms of typing and having to remember to do it.

It also falls apart in lots of other cases, due to the lots of people
use try to do classes. Since |constructor| is a property of the
prototype in JS, that breaks when people do:

function Foo() { /* ... /* }

Foo.prototype = {
/* ... Foo.prototype.constructor just died ... */
};

(Notice that if you use Foo.prototype.yourPropertyName = /* ... */,
Foo.prototype.yourMethodName = /* ... */, and so on for every property
and method, the constructor comparison still works.)

I realize the original scope of the discussion *here* is with IDL, but
if we start advocating for the constructor comparison approach, people
have to be conscious of where it doesn't work (i.e., in these cases) and
so they can't universally switch over to a new pattern. It reduces its
utility as a pattern.

--
Colby Russell
Reply all
Reply to author
Forward
0 new messages