Some differences between JavaScript engines

I gave my new fuzzer a break from testing TraceMonkey by asking it to look for differences between SpiderMonkey and JavaScriptCore. I have listed them below, with SpiderMonkey output above JavaScriptCore output.

I have no idea how many of these are bugs (in SpiderMonkey or JavaScriptCore) and how many are ambiguous in the spec (intentionally or unintentionally).

Early error reporting

SpiderMonkey reports some errors at compile time that JavaScriptCore only reports at run time, if the code is actually hit. The difference is most obvious (and most likely to cause compatibility problems) if the code is skipped.

> if (false) { --1; }
S: SyntaxError: invalid decrement operand
J: (no error)
> if (false) { return; }
S: SyntaxError: return not in function
J: (no error)

instanceof

The two engines disagree about what objects are reasonable operands for the 'instanceof' operator.

> ({} instanceof {a:2})
S: typein:3: TypeError: invalid 'instanceof' operand ({a:2})
J: false
> ({} instanceof eval)
S: false
J: Exception: TypeError: instanceof called on an object with an invalid prototype property.

new with native functions

SpiderMonkey allows the "new" operator to be used with some native functions that JavaScriptCore considers non-constructors.

> new Math.sqrt(16)
S: 4
J: Exception: TypeError: Result of expression 'Math.sqrt' ... is not a constructor.
> new ({}.toString)
S: [object Object]
J: Exception: TypeError: Result of expression '({}.toString)' ... is not a constructor.
> new eval
S: typein:9: EvalError: function eval must be called directly, and not by way of a function of another name
J: Exception: TypeError: Result of expression 'eval' ... is not a constructor.

Converting between numbers and strings

> print(+'\00000027')
S: NaN
J: 0
> (1e-10).toString(16)
S: 0.000000006df37f675ef6ec
J: 0

const

There are subtle differences in handling of this new keyword.

> const d; const d;
S: TypeError: redeclaration of const d
J: (no error)
> const c = 0; print(++c);
S: 0
J: 1

Other differences

> print((function(){return arguments;})());
S: [object Object]
J: [object Arguments]
> typeof /x/
S: object
J: function

See Mozilla bug 61911, which changed this in SpiderMonkey in 2007.

6 Responses to “Some differences between JavaScript engines”

  1. Jeff Walden Says:

    Either behavior for early-error is fine (16, attempting to call PutValue).

    SpiderMonkey is correct for the first instanceof, because native objects don’t implement [[HasInstance]] unless they’re functions. The second behavior, as far as I can tell, can go either way per the last paragraph of 15.1.2.1.

    new 4 is a SpiderMonkey bug (4 is not an Object). new ({}.toString) is ambiguous, I think, because functions only acquire [[Construct]] if they’re declared in a script that’s executed, but it’s not specified that natively-implemented functions don’t have [[Construct]]. new eval goes either way for the same reason as the previous paragraph.

    The first conversion test is JavaScriptCore’s bug; nuls aren’t allowed in strings. I bet they’re stopping stringification of the number after hitting a , in which case an empty string is 0. The latter case any radix but 10 in the range 2 to 36 is implementation-defined what’s returned, except that it’s a string.

    const is extension-land, no correct behavior yet.

    The first other difference is SpiderMonkey following the spec as it currently stands; I think that’s changing in ES3.next. The second is underspecified, in that nothing says only Function objects implement [[Call]].

  2. Jeff Walden Says:

    Jesse points out it’s not new 4, really new Math.sqrt with an argument, so that’s just the same thing as new ({}.toString). My mistake reading too quickly!

  3. Jeff Walden Says:

    “nuls aren’t allowed in the grammar for converting a string to a number”, sorry.

  4. Ian Hickson Says:

    Please file bugs where appropriate — either with WebKit, or Mozilla, or with the ECMAScript committee if the spec is vague. :-)

  5. Ajaxian » Playing with a fuzzy monkey; Helping JITs improve Says:

    [...] then put his fuzzer to work to find differences between Spidermonkey and JavaScriptCore. Interesting [...]

  6. pd Says:

    I’d really like to see this sort of analysis in a complete sense. I’m thinking a compatibility table like PPK’s quirksmode but instead of listing the different browser behaviours in relation to JavaScript events, common coding patterns and the varying behaviours of the different JS engines, would be a great benefit to developers.