Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Host object code for emulating Firefox document.all behavior?

26 views
Skip to first unread message

Norris Boyd

unread,
Jan 22, 2008, 5:48:28 PM1/22/08
to
We're trying to figure out the best way in Rhino to emulate Firefox/
SpiderMonkey's behavior of document.all. (I know document.all is
obsolete, etc., but Rhino is trying to support HtmlUnit, which in turn
must emulate existing browsers.) The problem, in brief, is that the
behavior appears non-ECMA, but the code in SpiderMonkey appears to be
ECMA compliant. My suspicion is that this works via some host object
magic, so I'm curious for more details so we might emulate the
behavior in Rhino.

Specifically, the expression
document.all ? true : false
results in false, but the expression
Boolean(document.all)
results in true. ECMA 9.2 specifies ToBoolean for Object converts to
true. Both the first operand of ? : (Section 11.12) and Boolean called
as a function (15.6.1) specify that ToBoolean should be used. What's
more, typeof document.all is "undefined", but "all" in document is
true.

From reading the SpiderMonkey source, I think that this conversion is
handled by js_ValueToBoolean:
http://lxr.mozilla.org/mozilla1.8.0/source/js/src/jsbool.c#184. This
function implements object -> true as ECMA specifies.

So how does this work? Can someone point me to a piece of host object
code in Firefox I could look at?

The relevant bug is https://bugzilla.mozilla.org/show_bug.cgi?id=412247.

Thanks,
Norris

smaug

unread,
Jan 22, 2008, 7:03:03 PM1/22/08
to

Igor Bukanov

unread,
Jan 23, 2008, 6:43:17 PM1/23/08
to Norris Boyd, dev-tech-...@lists.mozilla.org
On 23/01/2008, smaug <sm...@welho.com> wrote:
> Norris Boyd wrote:
> > We're trying to figure out the best way in Rhino to emulate Firefox/
> > SpiderMonkey's behavior of document.all. (I know document.all is
> > obsolete, etc., but Rhino is trying to support HtmlUnit, which in turn
> > must emulate existing browsers.) The problem, in brief, is that the
> > behavior appears non-ECMA, but the code in SpiderMonkey appears to be
> > ECMA compliant. My suspicion is that this works via some host object
> > magic, so I'm curious for more details so we might emulate the
> > behavior in Rhino.

> See what was done in
> https://bugzilla.mozilla.org/show_bug.cgi?id=248549

The main idea is to annotate in the generated bytecode the property
access with flags describing the nature of access. Then the native
code that is called to get/set properties can see that it was called
for in a boolean context, or in a method context or property access
context, see http://lxr.mozilla.org/seamonkey/source/js/src/jsobj.c#3159
.

Regards, Igor

VK

unread,
Jan 24, 2008, 10:14:05 AM1/24/08
to
On Jan 23, 1:48 am, Norris Boyd <norrisb...@gmail.com> wrote:
> Specifically, the expression
> document.all ? true : false
> results in false, but the expression
> Boolean(document.all)
> results in true.

Right, this is what required by ECMAScript specs. Javascript
implements both primitive boolean value and Boolean object wrapper. In
logical operations objects are being downcasted first to primitives
with Boolean(false) resulting in true in many circumstances. Try this
for instance in any browser:

<script>
var b1 = false;
var b2 = new Boolean(false);

/*1*/ window.alert(b1 ? 'true':'false'); // false
/*2*/ window.alert(b2 ? 'true':'false'); // true
</script>

The moral is that you never ever use Boolean wrapper for Javascript
except one very particular situation which is not presented here.

In your case document.all returns undefined which is in Boolean
constructor context equal to Boolean(false) which is situation /*2*/
in the sample above.

So the options are either to break Rhino compatibility with ECMAScript
or to use the right style of boolean operations. I actually highly
surprised that on
https://bugzilla.mozilla.org/show_bug.cgi?id=412247
people seem ready to rather patch Rhino like no big problem which is
sorry to say but IMO a total nonsense.

Mike Shaver

unread,
Jan 24, 2008, 10:18:56 AM1/24/08
to VK, dev-tech-...@lists.mozilla.org
On Jan 24, 2008 10:14 AM, VK <school...@yahoo.com> wrote:
> On Jan 23, 1:48 am, Norris Boyd <norrisb...@gmail.com> wrote:
> > Specifically, the expression
> > document.all ? true : false
> > results in false, but the expression
> > Boolean(document.all)
> > results in true.
>
> Right, this is what required by ECMAScript specs. Javascript
> implements both primitive boolean value and Boolean object wrapper. In
> logical operations objects are being downcasted first to primitives
> with Boolean(false) resulting in true in many circumstances.

I believe that ECMA permits *host* objects to have any conversion
behaviour they wish, no?

Mike

VK

unread,
Jan 24, 2008, 10:40:14 AM1/24/08
to
On Jan 24, 6:18 pm, "Mike Shaver" <mike.sha...@gmail.com> wrote:
> I believe that ECMA permits *host* objects to have any conversion
> behaviour they wish, no?

No. It does allow them though to return platform-specific strings for
typeof operator. Say
typeof SomeActiveXObject == 'unknown'
for some ActiveX on IE and it is standard compliant. It is all
irrelevant to the current question any way, because
var foo = new Boolean(WhateverWhatsoever);
foo ? This() : That();
is fully under the ECMAScript regulation so has to act in the way it
is specified - and in the way it will actually act on any Javascript
enabled browser.
Personal coding preferences of a particular developer should not
override the specification IMO ;-)


Attila Szegedi

unread,
Jan 24, 2008, 10:59:13 AM1/24/08
to Mike Shaver, VK, dev-tech-...@lists.mozilla.org
Section 8.6.2 says host objects can implement internal properties any
way they wish (including [[DefaultValue]](hint)) , however ToBoolean
type conversion as defined in section 9.2 doesn't use [[DefaultValue]]
(Boolean).

Section 9.2. says ToBoolean converts any Object to true, and doesn't
distinguish between a host object and native object. Arguably, the
spec doesn't say whether host objects are Objects (with capital O), in
which case it'd actually not define boolean conversion of host objects
at all.

Finally, 8.6.2.6 defines [[DefaultValue]] for native objects and
_only_ for Number and String hints, suggesting it is not meant to be
used with any other hints anyway (and indeed isn't used with any other
hints in the spec).

All of these imply to me that host objects can not affect their
boolean evaluation according to the ES3 spec -- an if statement will
perform ToBoolean on its argument, and ToBoolean will return true for
any Object.

Attila.

On 2008.01.24., at 16:18, Mike Shaver wrote:

> On Jan 24, 2008 10:14 AM, VK <school...@yahoo.com> wrote:

>> On Jan 23, 1:48 am, Norris Boyd <norrisb...@gmail.com> wrote:
>>> Specifically, the expression
>>> document.all ? true : false
>>> results in false, but the expression
>>> Boolean(document.all)
>>> results in true.
>>
>> Right, this is what required by ECMAScript specs. Javascript
>> implements both primitive boolean value and Boolean object wrapper.
>> In
>> logical operations objects are being downcasted first to primitives
>> with Boolean(false) resulting in true in many circumstances.
>

> I believe that ECMA permits *host* objects to have any conversion
> behaviour they wish, no?
>

> Mike

Igor Bukanov

unread,
Jan 24, 2008, 11:01:45 AM1/24/08
to Mike Shaver, VK, dev-tech-...@lists.mozilla.org
On 24/01/2008, Mike Shaver <mike....@gmail.com> wrote:
> On Jan 24, 2008 10:14 AM, VK <school...@yahoo.com> wrote:
...

> > Right, this is what required by ECMAScript specs. Javascript
> > implements both primitive boolean value and Boolean object wrapper. In
> > logical operations objects are being downcasted first to primitives
> > with Boolean(false) resulting in true in many circumstances.
>
> I believe that ECMA permits *host* objects to have any conversion
> behaviour they wish, no?

And since ES3 permits host objects to return different values each
time a property is accessed, it is perfectly ok for a host object to
return undefined for document.all when it is accessed in the boolean
operation context and to return an object in the other cases.

Regards, Igor

VK

unread,
Jan 24, 2008, 11:05:06 AM1/24/08
to
On Jan 24, 6:40 pm, VK <schools_r...@yahoo.com> wrote:
> var foo = new Boolean(WhateverWhatsoever);
> foo ? This() : That();
> is fully under the ECMAScript regulation so has to act in the way it
> is specified - and in the way it will actually act on any Javascript
> enabled browser.
> Personal coding preferences of a particular developer should not
> override the specification IMO ;-)

In the OP's case the whole problem is solved per ECMAScript by
implicitly downcasting the Boolean object before using in ternary
operator:

var b1 = false;
var b2 = new Boolean(false);

alert(b1 ? 'true':'false'); // always OK
alert(b2 ? 'true':'false'); // Oops
alert((b2==true) ? 'true':'false'); // OK again

Really, should one type in (b2==true) as expected or to hack the
engine every time it doesn't behave as "me wanted"? I keep staying on
the first option :-)


Mike Shaver

unread,
Jan 24, 2008, 11:07:07 AM1/24/08
to Attila Szegedi, VK, dev-tech-...@lists.mozilla.org
On Jan 24, 2008 10:59 AM, Attila Szegedi <szeg...@gmail.com> wrote:
> Section 8.6.2 says host objects can implement internal properties any
> way they wish (including [[DefaultValue]](hint)) , however ToBoolean
> type conversion as defined in section 9.2 doesn't use [[DefaultValue]]
> (Boolean).

Boolean(document.all) is true, AFAIK, and

alert(document.all ? "d.a" : "no d.a")

is governed by 11.12's steps 1 and 2 here. Our document host object
chooses to implement the getter for "all" in a way that depends on how
it's accessed, and I can't find any stricture in ECMA that would
require otherwise. (If there were one, dynamic properties like
document.all.foo would seem to be entirely impossible, since their
value depends on extra-script decisions and context as well.)

Once you _have_ a DocumentAll object by accessing document.all, I
don't believe its value conversion varies in any way counter to ECMA.
That you sometimes get a false value from the document.all getter is
entirely legal as far as I'm able to tell from my readings of ECMA.

Mike

Igor Bukanov

unread,
Jan 24, 2008, 11:08:18 AM1/24/08
to Attila Szegedi, VK, dev-tech-...@lists.mozilla.org, Mike Shaver
On 24/01/2008, Attila Szegedi <szeg...@gmail.com> wrote:
> Section 9.2. says ToBoolean converts any Object to true, and doesn't
> distinguish between a host object and native object. Arguably, the
> spec doesn't say whether host objects are Objects (with capital O), in
> which case it'd actually not define boolean conversion of host objects
> at all.

But this is not about the boolean conversion. Try in Firefox

javascript:(document.all?1:0)
javascript:(Boolean(document.all)?1:0)

The first returns 0 since as the implementation in a boolean-checking
returns undefined for document.all. The second result gives 1 as here
document.all is in the argument-of-a-call context and the result is
the real object.

Regards, Igor

VK

unread,
Jan 24, 2008, 11:09:28 AM1/24/08
to
On Jan 24, 7:05 pm, VK <schools_r...@yahoo.com> wrote:
> implicitly downcasting

damn, I'm having typing disorder today...
"explicitly downcasting "

Attila Szegedi

unread,
Jan 24, 2008, 11:30:06 AM1/24/08
to Mike Shaver, VK, dev-tech-...@lists.mozilla.org

On 2008.01.24., at 17:07, Mike Shaver wrote:

> On Jan 24, 2008 10:59 AM, Attila Szegedi <szeg...@gmail.com> wrote:
>> Section 8.6.2 says host objects can implement internal properties any
>> way they wish (including [[DefaultValue]](hint)) , however ToBoolean
>> type conversion as defined in section 9.2 doesn't use
>> [[DefaultValue]]
>> (Boolean).
>
> Boolean(document.all) is true, AFAIK, and
>
> alert(document.all ? "d.a" : "no d.a")
>
> is governed by 11.12's steps 1 and 2 here. Our document host object
> chooses to implement the getter for "all" in a way that depends on how
> it's accessed, and I can't find any stricture in ECMA that would
> require otherwise. (If there were one, dynamic properties like
> document.all.foo would seem to be entirely impossible, since their
> value depends on extra-script decisions and context as well.)

So document sometimes returns a boolean from [[Get]]("all"), and
sometimes returns an object. That's okay. But how can it decide what
to return? In other words, how does it detect "how it is accessed"?
(I'm really trying to understand this).

Attila.

Igor Bukanov

unread,
Jan 24, 2008, 11:38:17 AM1/24/08
to Attila Szegedi, VK, dev-tech-...@lists.mozilla.org, Mike Shaver
On 24/01/2008, Attila Szegedi <szeg...@gmail.com> wrote:
> So document sometimes returns a boolean from [[Get]]("all"), and
> sometimes returns an object.

It either returns undefined or an object.

> But how can it decide what
> to return? In other words, how does it detect "how it is accessed"?

In abstract terms the generated bytecode contains the necessary
information to describe the context of the call and that information
is passed to the native code responsible for the property access.
Implementation wise the property-access code in SpiderMonkey just
analyzes instructions in the bytecode that follows the property access
and adjusts the result accordingly.

Regards, Igor

VK

unread,
Jan 24, 2008, 11:41:47 AM1/24/08
to
On Jan 24, 7:07 pm, "Mike Shaver" <mike.sha...@gmail.com> wrote:
> Our document host object
> chooses to implement the getter for "all" in a way that depends on how
> it's accessed, and I can't find any stricture in ECMA that would
> require otherwise.

You are still missing the point. Your document host object may return
anything you like as long as doesn't lead to feature spoofing, so
would be not interpreted as "feature is here" while feature is
missing. At this point I was wrong by saying that you have not such
right: you do - but lesser browser producers explore some freedom
rights so better for the community ;-) and this is such cases, so ol'
good undefined would be just perfect. Yet the table 9.2 gives you four
options for return value for a missing host property:
boolean true/false
Boolean(true/false)
undefined
null
0
""

Again: it is not the problem, the problem how an ECMAScript-compliant
engine has to handle any of such value if wrapped using Boolean
constructor. In the ternary operator an ECMAScript-compliant engine
has to resolve such Boolean object by default as true, no matter if it
is a wrapper over false or true.
var bool = new Boolean(false); // null, "", true, etc.
bool ? doTrue() : doFalse();
must branch onto doTrue, period.

If Boolean wrapper is really needed - I cannot think of a circumstance
but say if - then one needs explicit downcasting here to prevent false
positives. It is either
(bool == true) ? doTrue() : doFalse();
as already suggested or even more simple
!bool ? doTrue() : doFalse();

In any shall perform case the engine itself has to be patched in non-
ECMA way. For all complains of the kind one may suggest to read
ECMAScript 3rd ed. and/or forward to comp.lang.javascript for further
education :-)


0 new messages