Make Intl object initialization lazy

RESOLVED FIXED in mozilla27

Status

()

Core
JavaScript: Internationalization API
RESOLVED FIXED
4 years ago
3 years ago

People

(Reporter: Waldo, Assigned: Waldo)

Tracking

unspecified
mozilla27
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(4 attachments)

Creating Collator instances requires a bunch of slow work.  The same's true for the other Intl classes.  If we can delay that work until it's actually needed (while preserving semantics), we can probably speed some stuff up, most notably startup time when standard classes get initialized.

This patch stack of fixing and hackitudinousness passes Intl/ and test262/intl402 jstests.  Tryservering now, may or may not work at all (but jstests results have me hopeful), perf behavior totally untested.

https://tbpl.mozilla.org/?tree=Try&rev=70a47cbfac44 (before)
https://tbpl.mozilla.org/?tree=Try&rev=1b2536c2a300 (after)
Here's a comparison with some recent m-c runs:

http://perf.snarkfest.net/compare-talos/index.html?oldRevs=1fda74e33e06,d50f590056fd,4df586670d2a,f97307cb4c95,8b4d14afc4f6,ecbb024abcee&newRev=1b2536c2a300&submit=true

Assuming the Ubuntu 64 regression isn't real (which I think), tpaint is good, now. However, the tp5o regressions on OS X and Win look real to me. No idea what's going on with them.

Let's maybe land this stuff and I'll do another round of callgrinding?
Created attachment 811429 [details] [diff] [review]
Adust how the Intl-initialized status, and internal properties, of an Intl-initialized object are represented

This is the guts of the change.  Right now, an object is an Intl object if it exists in the internalsMap, and the associated value is an object storing its internal proeprties.  Afterward, the associated value is an object, but the object has three properties -- .type, .lazyData, and .internalProps -- that together determine what kind of Intl object it is, whether its internal properties have been resolved, or whether it's storing computed data sufficient to determine its internal properties lazily.  The comment in initializeIntlObject is the place to start for a full description.  The various helper functions added will get used in subsequent patches to fix up Collator, DateTimeFormat, and NumberFormat to work with this scheme.
Attachment #811429 - Flags: review?(till)
Created attachment 811433 [details] [diff] [review]
Initialize Collator objects lazily

Now's where the real fun begins.  :-)

Each kind of Intl object is initialized through an InitializeFoo method.  Right now, those read basically as you'd expect.  To compute internal properties lazily, we have to split those methods into two.

One half does all observable processing of the arguments -- converting arrays to internal lists that don't invoke getters and setters, converting values to strings as appropriate, etc.  All the post-processed data then gets shoved into a .lazyData object associated with the object via the internals amp.

The second half is responsible for converting a .lazyData object into an actual object storing internal properties.  It does all the work from InitializeFoo that can be done whenever, and isn't observably performed in InitializeFoo.

It's somewhat tricky determining what can go in each half.  You basically have to know what every part of InitializeFoo *could* do, and whether it can reenter user script or not.  This passes test262/intl402, so presumably it's doing at least a moderately good job of getting the side effects happening at the right times.  And a bunch of the "resolve" work is straightforwardly invisible, because it's just property-copying between two objects without unusual prototypes.  But it's always possible I missed something.  Close eyes appreciated.  :-)
Attachment #811433 - Flags: review?(till)
Created attachment 811434 [details] [diff] [review]
Initialize NumberFormat objects lazily
Attachment #811434 - Flags: review?(till)
Created attachment 811435 [details] [diff] [review]
Initialize DateTimeFormat objects lazily
Attachment #811435 - Flags: review?(till)
Comment on attachment 811429 [details] [diff] [review]
Adust how the Intl-initialized status, and internal properties, of an Intl-initialized object are represented

Review of attachment 811429 [details] [diff] [review]:
-----------------------------------------------------------------

This hasn't exactly become simpler, but with the excellent documentation, it's ok, I think.

::: js/src/builtin/Intl.js
@@ +911,4 @@
>  var internalsMap = new WeakMap();
>  
>  
> +/** Set the [[initializedIntlObject]] internal property of |obj| to true. */

Either format this block over three lines, or make it a line comment. I don't really care which, though the first is probably more common.

@@ +926,5 @@
> +    // nothing else.  No other property of |internals| can be used.  (This
> +    // occurs when InitializeCollator or similar marks an object with this but
> +    // fails before it can also mark the object as a Collator or similar,
> +    // leaving the object in limbo as an Intl object, but not a Collator, and
> +    // it being impossible to actually make it a Collator.)

Maybe "(This occurs when InitializeCollator or similar marks an object as [[initializedIntlObject]], but fails before marking it as the appropriate more-specific type (i.e., Collator, DateTimeFormat or NumberFormat).)"

@@ +938,5 @@
> +    // If |internals| doesn't have a "partial" .type, two additional properties
> +    // have meaning.  The .lazyData property stores information needed to
> +    // compute -- without observable side effects -- the actual internal Intl
> +    // properties of |obj|.  If it is non-null, then the actual internal
> +    // properties haven't been computed, and .lazyData must be processed before

"processed by setInternalProperties"?

@@ +952,5 @@
>      return internals;
>  }
>  
>  
> +/** Mark |internals| as having the given type and lazy data. */

Same formatting request as above

@@ +988,5 @@
> + */
> +function maybeInternalProperties(internals)
> +{
> +    assert(IsObject(internals), "non-object passed to maybeInternalProperties");
> +    assert(internals.type !== "partial", "should only be used by knowledgeable callers");

While that is certainly true, maybe something like "maybeInternalProperties must only be used on properly initialized |internals| objects" is closer to what's actually tested here?

@@ +1011,5 @@
> + * Check that |obj| meets the requirements for "this Collator object", "this
> + * NumberFormat object", or "this DateTimeFormat object" as used in the method
> + * with the given name.  Throw a TypeError if |obj| doesn't meet these
> + * requirements.  But if it does, return |obj|'s internals object (*not* the
> + * object holding its internal properties!), associated with it by

This is the part of all of this that's the hardest to understand. It'd be nice to find a nomenclature that better separates |internals| and "object holding internal properties". I don't have a good idea for that, though, and at least the documentation is excellent.

@@ +1022,5 @@
> +function getIntlObjectInternals(obj, className, methodName) {
> +    assert(typeof className === "string", "bad className for getIntlObjectInternals");
> +
> +    var internals = callFunction(std_WeakMap_get, internalsMap, obj);
> +    assert(internals === undefined || IsObject(internals), "bad mapping in internalsMap");

I think this should be `!callFunction(std_WeakMap_has, internalsMap, obj) || IsObject(internals)`

@@ +1042,5 @@
> +function getInternals(obj)
> +{
> +    assert(isInitializedIntlObject(obj), "for use only on guaranteed Intl objects");
> +
> +    var internals = callFunction(std_WeakMap_get, internalsMap, obj);

Maybe assert IsObject(internals)? Or add the last three checks from getIntlObjectInternals to isInitializedIntlObject. Then that could even be used in getIntlObjectInternals.

@@ +1050,5 @@
> +    var lazyData = internals.lazyData;
> +    if (!lazyData)
> +        return internals.internalProps;
> +
> +    assert(type === "Collator" || type === "DateTimeFormat" || type === "NumberFormat", "unexpected type");

isInitializedIntlObject could also assert (.type === 'partial' || type === ...) and the rest of the internal-consistency stuff.
Attachment #811429 - Flags: review?(till) → review+
Comment on attachment 811433 [details] [diff] [review]
Initialize Collator objects lazily

Review of attachment 811433 [details] [diff] [review]:
-----------------------------------------------------------------

Nice. r=me with nits addressed.

Somewhat unrelated, I worry about the pre-existing Collator.foo usages. I can't see why they wouldn't cause the self-hosting compartment's Collator object to be deep-cloned into the content compartment. At least now that happens lazily, but ideally it wouldn't happen at all.

::: js/src/builtin/Intl.js
@@ +1080,4 @@
>  };
>  
>  
> +/** Compute an internal properties object from |lazyCollatorData|. */

Formatting (and no, I don't *truly* care)

@@ +1096,5 @@
>      // Step 9.
> +    var collatorIsSorting = lazyCollatorData.usage === "sort";
> +    var localeData = collatorIsSorting
> +                     ? Collator.sortLocaleData
> +                     : Collator.searchLocaleData;

Here and in line 1107, Collator.foo is used. If I'm not missing something, this causes the self-hosting compartment's instance of Collator to be cloned into the content compartment wholesale. If possible, it'd be much better to follow the usual std_foo_bar pattern.

@@ +1105,3 @@
>  
>      // Step 15.
>      var r = ResolveLocale(Collator.availableLocales(),

resolvedLocale?

@@ +1140,5 @@
>      }
>  
>      // Compute remaining collation options.
> +    // Steps 21-22.
> +    var s = lazyCollatorData.rawSensitivity;

And, of course `sensitivity`

@@ +1193,5 @@
> + * This method is complicated a moderate bit by its implementing initialization
> + * as a *lazy* concept.  Everything that must happen now, does -- but we defer
> + * all the work we can until the object is actually used as a Collator.  This
> + * later work occurs in |resolveCollatorInternals|, and the steps not noted
> + * here generally occur there.

Not "generally". If they don't occur here or there, their omission and the reason for it should at least be explained - making them "occur" in one of the two places, after all.

@@ +1220,5 @@
> +    //         kf: "upper" / "lower" / "false" / undefined
> +    //       }
> +    //     rawSensitivity: "base" / "accent" / "case" / "variant" / undefined,
> +    //     ignorePunctuation: true / false
> +    //   }

Nice!

@@ +1235,5 @@
> +    // Steps 4-5.
> +    //
> +    // If we ever need more speed here at startup, we should try to detect the
> +    // case where |options === undefined| and Object.prototype hasn't been
> +    // mucked with.  For now, keep it simple if we can.

What happens if Object.prototype is changed at some point after this potential optimization is applied and before options are resolved? If that doesn't matter: great. Maybe explain why/how for future reference. If it does, remove the comment.

@@ +1244,5 @@
> +
> +    // Compute options that impact interpretation of locale.
> +    // Step 6.
> +    var u = GetOption(options, "usage", "string", ["sort", "search"], "sort");
> +    lazyCollatorData.usage = u;

Pre-existing, but can you s/u/usage/?

@@ +1267,5 @@
> +    // Compute remaining collation options.
> +    // Step 20.
> +    var s = GetOption(options, "sensitivity", "string",
> +                      ["base", "accent", "case", "variant"], undefined);
> +    lazyCollatorData.rawSensitivity = s;

Same here: s/s/sensitivity/

@@ +1271,5 @@
> +    lazyCollatorData.rawSensitivity = s;
> +
> +    // Step 23.
> +    var ip = GetOption(options, "ignorePunctuation", "boolean", undefined, false);
> +    lazyCollatorData.ignorePunctuation = ip;

And here

@@ +1276,4 @@
>  
>      // Step 26.
> +    //
> +    // Everything that must happen now, is done: mark the lazy data as fully

That comma looks wrong to me, but I'm probably wrong about it being wrong

@@ +1367,4 @@
>   */
>  function Intl_Collator_compare_get() {
>      // Check "this Collator object" per introduction of section 10.3.
> +    var internals = getCollatorInternals(this, "compare");

This is much more understandable than before. Nice.
Attachment #811433 - Flags: review?(till) → review+
Comment on attachment 811433 [details] [diff] [review] [diff] [review]
Initialize Collator objects lazily

Oh, and I looked at the "is it ok to initialize this lazily" aspect very closely, and am fairly convinced that it's correct.
Comment on attachment 811434 [details] [diff] [review]
Initialize NumberFormat objects lazily

Review of attachment 811434 [details] [diff] [review]:
-----------------------------------------------------------------

Looks good, I couldn't find any over-eager setting of properties, or lazy-setting of ones that must be set eagerly.

Again, I'm worried by NumberFormat.foo permeating this code. Most definitely out of scope for this patch, but we should probably do something about it in a follow-up.

::: js/src/builtin/Intl.js
@@ +1432,5 @@
> +    relevantExtensionKeys: ["nu"]
> +};
> +
> +
> +/** Compute an internal properties object from |lazyNumberFormatData|. */

You know what I mean

@@ +1453,5 @@
> +    // Step 10.
> +    var localeData = NumberFormat.localeData;
> +
> +    // Step 11.
> +    var r = ResolveLocale(NumberFormat.availableLocales(),

resolvedLocale?

@@ +1465,5 @@
> +    internalProps.numberingSystem = r.nu;
> +
> +    // Compute formatting options.
> +    // Step 16.
> +    var s = lazyNumberFormatData.style;

style?

@@ +1488,5 @@
> +    if ("minimumSignificantDigits" in lazyNumberFormatData) {
> +        // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
> +        // actual presence (versus undefined-ness) of these properties.
> +        internalProps.minimumSignificantDigits = lazyNumberFormatData.minimumSignificantDigits;
> +        internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits;

assert("maximumSignificantDigits" in lazyNumberFormatData), maybe?

@@ +1530,5 @@
> + * This method is complicated a moderate bit by its implementing initialization
> + * as a *lazy* concept.  Everything that must happen now, does -- but we defer
> + * all the work we can until the object is actually used as a NumberFormat.
> + * This later work occurs in |resolveCollatorInternals|, and the steps not
> + * noted here generally occur there.

Same as in the Collator patch: "generally" shouldn't enter the picture at all.

@@ +1583,5 @@
>      // Steps 4-5.
> +    //
> +    // If we ever need more speed here at startup, we should try to detect the
> +    // case where |options === undefined| and Object.prototype hasn't been
> +    // mucked with.  For now, keep it simple if we can.

Same question as in the Collator patch
Attachment #811434 - Flags: review?(till) → review+
Comment on attachment 811434 [details] [diff] [review]
Initialize NumberFormat objects lazily

Review of attachment 811434 [details] [diff] [review]:
-----------------------------------------------------------------

::: js/src/builtin/Intl.js
@@ +1571,5 @@
> +    //     useGrouping: true / false,
> +    //   }
> +    //
> +    // Note that lazy data is only installed as a final step of initialization,
> +    // so every Collator lazy data object has *all* these properties, never a

I overlooked this, earlier: s/Collator/NumberFormat/
Comment on attachment 811435 [details] [diff] [review]
Initialize DateTimeFormat objects lazily

Review of attachment 811435 [details] [diff] [review]:
-----------------------------------------------------------------

Looks good, modulo nits and the by-now-familiar open questions.

::: js/src/builtin/Intl.js
@@ +1846,4 @@
>  /********** Intl.DateTimeFormat **********/
>  
>  
> +/** Compute an internal properties object from |lazyDateTimeFormatData|. */

...

@@ +1846,5 @@
>  /********** Intl.DateTimeFormat **********/
>  
>  
> +/** Compute an internal properties object from |lazyDateTimeFormatData|. */
> +function resolveDateTimeInternals(lazyDateTimeFormatData) {

Maybe this (and the analogous Collator and NumberFormat) function(s) should be capitalized to match InitializeFoo?

@@ +1873,5 @@
> +    //     formatMatcher: "basic" / "best fit",
> +    //   }
> +    //
> +    // Note that lazy data is only installed as a final step of initialization,
> +    // so every Collator lazy data object has *all* these properties, never a

s/Collator/DateTimeFormat/

@@ +1886,5 @@
> +    // Step 9.
> +    var localeData = DateTimeFormat.localeData;
> +
> +    // Step 10.
> +    var r = ResolveLocale(DateTimeFormat.availableLocales(),

resolvedLocale

@@ +1924,5 @@
> +
> +
> +/**
> + * Returns an object containing the NumberFormat internal properties of |obj|,
> + * or throws a TypeError if |obj| isn't NumberFormat-initialized.

s/NumberFormat/DateTimeFormat/ twice

@@ +1939,5 @@
> +    // Otherwise it's time to fully create them.
> +    internalProps = resolveDateTimeInternals(internals.lazyData);
> +    setInternalProperties(internals, internalProps);
> +    return internalProps;
> +}

Looking at essentially the same function for the third time, I wonder if it should be unified to something like
function getResolvedIntlObjectInternals(obj, methodName, objType, lazyDataResolver)

where
objType = "Collator"|"NumberFormat"|"DateTimeFormat"
lazyDataResolver = resolveCollatorInternals|resolveNumberInternals|resolveDateTimeInternals

@@ +1945,2 @@
>  /**
>   * Components of date and time formats and their values.

Add more information about the initialization's laziness here, analogous to Collator and NumberFormat, please

@@ +2001,5 @@
> +    //     formatMatcher: "basic" / "best fit",
> +    //   }
> +    //
> +    // Note that lazy data is only installed as a final step of initialization,
> +    // so every Collator lazy data object has *all* these properties, never a

s/Collator/DateTimeFormat/
Attachment #811435 - Flags: review?(till) → review+
Norbert, in step 22 of InitializeDateTimeFormat, Waldo added this comment:

// Step 22.
//
// For some reason (ICU not exposing enough interface?) we drop the
// requested format matcher on the floor after this. In any case, even if
// doing so is justified, we have to do this work here in case it triggers
// getters or similar.

Can you shed light on whether something is actually missing here, and, if not, why it makes sense to not use the format matcher?
Flags: needinfo?(mozillabugs)

Comment 13

4 years ago
The "formatMatcher" is dropped because only the best-fit algorithm is implemented, so basic == best-fit for now. It may be possible to implement the basic format algorithm by inspecting the supported skeletons for each locale [1]. But Norbert is the expert here! :)

[1] https://github.com/anba/es6draft/blob/master/src/main/java/com/github/anba/es6draft/runtime/objects/intl/DateTimeFormatConstructor.java#L407

Comment 14

4 years ago
"supported skeletons for each locale" -> udatpg_openSkeletons function in ICU4C.
I've got all the changes made locally, will push in the morning.

Bugzilla archaeology may be able to answer the basic/best-fit question.  I'd be somewhat surprised if I didn't ask it back when reviewing the initial patches.  But it's late here, so I'm not looking now.  :-)

(In reply to Till Schneidereit [:till] from comment #6)
> This hasn't exactly become simpler, but with the excellent documentation,
> it's ok, I think.

Yeah, that's about what I was hoping for.

> @@ +1011,5 @@
> > + * Check that |obj| meets the requirements for "this Collator object", "this
> > + * NumberFormat object", or "this DateTimeFormat object" as used in the method
> > + * with the given name.  Throw a TypeError if |obj| doesn't meet these
> > + * requirements.  But if it does, return |obj|'s internals object (*not* the
> > + * object holding its internal properties!), associated with it by
> 
> This is the part of all of this that's the hardest to understand. It'd be
> nice to find a nomenclature that better separates |internals| and "object
> holding internal properties". I don't have a good idea for that, though, and
> at least the documentation is excellent.

Yeah, I didn't have good ideas here either.

(In reply to Till Schneidereit [:till] from comment #7)
> Somewhat unrelated, I worry about the pre-existing Collator.foo usages. I
> can't see why they wouldn't cause the self-hosting compartment's Collator
> object to be deep-cloned into the content compartment. At least now that
> happens lazily, but ideally it wouldn't happen at all.

It doesn't happen at all.  Those Collator.foo usages (and same for the other methods) refer to a local-variable Collator, that is actually |collatorInternalProperties|.  Ditto for the other two object classes.  The names shadowing the global is an artifact of the spec algorithms referring to [[foo]] properties of the Collator constructor object, and similar, and wanting to preserve the spec naming for stuff as much as possible for readability.  But we don't store the properties directly on Collator because we don't have anything like hidden properties, so our setup is slightly different.  (It was incredibly helpful, when making the transformations in these patches, to have step-by-step commenting by everything, and spec-identical naming for everything.  It would have taken a lot longer to do any of this if I'd had to sort through an undistinguished mass of code not directly correlating with the spec.)

> @@ +1105,3 @@
> >  
> >      // Step 15.
> >      var r = ResolveLocale(Collator.availableLocales(),
> 
> resolvedLocale?
> 
> @@ +1140,5 @@
> >      }
> >  
> >      // Compute remaining collation options.
> > +    // Steps 21-22.
> > +    var s = lazyCollatorData.rawSensitivity;
> 
> And, of course `sensitivity`
>
> @@ +1244,5 @@
> > +
> > +    // Compute options that impact interpretation of locale.
> > +    // Step 6.
> > +    var u = GetOption(options, "usage", "string", ["sort", "search"], "sort");
> > +    lazyCollatorData.usage = u;
> 
> Pre-existing, but can you s/u/usage/?
>
> @@ +1267,5 @@
> > +    // Compute remaining collation options.
> > +    // Step 20.
> > +    var s = GetOption(options, "sensitivity", "string",
> > +                      ["base", "accent", "case", "variant"], undefined);
> > +    lazyCollatorData.rawSensitivity = s;
> 
> Same here: s/s/sensitivity/
>
> @@ +1271,5 @@
> > +    lazyCollatorData.rawSensitivity = s;
> > +
> > +    // Step 23.
> > +    var ip = GetOption(options, "ignorePunctuation", "boolean", undefined, false);
> > +    lazyCollatorData.ignorePunctuation = ip;
> 
> And here
>
> @@ +1465,5 @@
> > +    internalProps.numberingSystem = r.nu;
> > +
> > +    // Compute formatting options.
> > +    // Step 16.
> > +    var s = lazyNumberFormatData.style;
> 
> style?

|r|, |s|, |u|, |ip| are the exact names used in the spec:

http://www.ecma-international.org/ecma-402/1.0/#sec-10.1.1.1

The old code, and this code, uses exactly those names (when referring to the exact same value) to ease correlation against the spec language.  I think it's easier to see that |r|, say, is used correctly when its use flows into something exactly in the spec, rather than having to think twice to map |resolvedLocale| in the implementation to the |r| in the spec.

> @@ +1235,5 @@
> > +    // Steps 4-5.
> > +    //
> > +    // If we ever need more speed here at startup, we should try to detect the
> > +    // case where |options === undefined| and Object.prototype hasn't been
> > +    // mucked with.  For now, keep it simple if we can.
> 
> What happens if Object.prototype is changed at some point after this
> potential optimization is applied and before options are resolved?

Doesn't matter.  |options| is consumed fully in each of the InitializeFoo methods to construct an |opt| object whose data is totally untouchable by content (null prototype chain, primitive properties or curtailed things like Lists that aren't affected by content).  Same for all the other stuff shoved into lazyData.  So the state of the world when resolveFooInternals happens, doesn't matter.

> @@ +1276,4 @@
> >  
> >      // Step 26.
> > +    //
> > +    // Everything that must happen now, is done: mark the lazy data as fully
> 
> That comma looks wrong to me, but I'm probably wrong about it being wrong

It's probably stretching the bounds of proper grammar in pursuit of being unambiguous.  I rewrote slightly to eliminate the issue.

(In reply to Till Schneidereit [:till] from comment #11)
> > +/** Compute an internal properties object from |lazyDateTimeFormatData|. */
> > +function resolveDateTimeInternals(lazyDateTimeFormatData) {
> 
> Maybe this (and the analogous Collator and NumberFormat) function(s) should
> be capitalized to match InitializeFoo?

Most self-hosted helper functions appear to be camelCaps.  InitializeFoo is InterCaps only because the spec methods in question are named so.  So I'm inclined to leave it as-is.

> > +    // Note that lazy data is only installed as a final step of initialization,
> > +    // so every Collator lazy data object has *all* these properties, never a
> 
> s/Collator/DateTimeFormat/

Hmm, I had an awful lot of these, didn't I.  Oh well.

> Looking at essentially the same function for the third time, I wonder if it
> should be unified to something like
> function getResolvedIntlObjectInternals(obj, methodName, objType,
> lazyDataResolver)
> 
> where
> objType = "Collator"|"NumberFormat"|"DateTimeFormat"
> lazyDataResolver =
> resolveCollatorInternals|resolveNumberInternals|resolveDateTimeInternals

I'd like to see getCollatorInternals or similar at call sites, so that there are as few arguments as possible to mess up.  As far as having one method with argument-directed dispatch, I shied away from it to keep JITs happier, but this could be paranoia.  If you feel strongly we can change in a followup bug/patch, but let's move with this to get this landed.

> @@ +1945,2 @@
> >  /**
> >   * Components of date and time formats and their values.
> 
> Add more information about the initialization's laziness here, analogous to
> Collator and NumberFormat, please

I assume you meant this by resolveDateTimeFormatInternals or whatever the method was named.

Comment 16

4 years ago
(In reply to Till Schneidereit [:till] from comment #12)

> Norbert, in step 22 of InitializeDateTimeFormat, Waldo added this comment:
> 
> // For some reason (ICU not exposing enough interface?) we drop the
> // requested format matcher on the floor after this. In any case, even if
> // doing so is justified, we have to do this work here in case it triggers
> // getters or similar.
> 
> Can you shed light on whether something is actually missing here, and, if
> not, why it makes sense to not use the format matcher?

What André said in comment 13. See also bug 852837.
Flags: needinfo?(mozillabugs)
A try run without Intl:

https://tbpl.mozilla.org/?tree=Try&rev=80e4763e6a81

And one with Intl enabled, for correctness-verification and perf-comparison:

https://tbpl.mozilla.org/?tree=Try&rev=2c2e32a96b7c
https://tbpl.mozilla.org/?tree=Try&rev=140ff096cf88 to hopefully get the test_interfaces.html-fixing correct.
Blocks: 900286
https://hg.mozilla.org/mozilla-central/rev/1d6b119b7281
Status: ASSIGNED → RESOLVED
Last Resolved: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla27
Mass-moving existing Intl-related bugs to the new Core :: JavaScript: Internationalization API component.

If you think this bug has been moved in error, feel free to move it back to Core :: JavaScript Engine.

[Mass change filter: core-js-intl-api-move]
Component: JavaScript Engine → JavaScript: Internationalization API
You need to log in before you can comment on or make changes to this bug.