Bug 153679

Summary: [INTL] Intl Constructors not web compatible with Object.create usage
Product: WebKit Reporter: Andy VanWagoner <andy>
Component: JavaScriptCoreAssignee: Andy VanWagoner <andy>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, erights, keith_miller, mark.lam, msaboff, ossy, rniwa, saam, sukolsak
Priority: P2    
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 155300, 155308    
Bug Blocks: 90906    
Attachments:
Description Flags
Patch
none
Patch none

Andy VanWagoner
Reported 2016-01-29 15:39:24 PST
The second version of ECMA-402 removed the ability to call Collator, DateTimeFormat, and NumberFormat with an already created `this` value to re-initialize. All calls without `new` instead create a new object, instead of trying to initialize an arbitrary `this`. The new behavior breaks this pattern used in a actual websites: var format = Object.create(Intl.NumberFormat.prototype) Intl.NumberFormat.apply(format, args) The 3rd version will likely re-allow this pattern. While arbitrary objects will not possible to initialize as a Collator, DateTimeFormat, or NumberFormat, objects inheriting from these prototypes can be. The implementation of Intl constructors in WebKit should be made web-compatible and forward-compatible with this pattern.
Attachments
Patch (16.03 KB, patch)
2016-02-27 16:19 PST, Andy VanWagoner
no flags
Patch (16.68 KB, patch)
2016-03-09 06:58 PST, Andy VanWagoner
no flags
Andy VanWagoner
Comment 1 2016-01-29 15:42:12 PST
Mark S. Miller
Comment 3 2016-02-21 08:57:01 PST
Unlike the github bug thread or what we heard at the tc39 mtg, the first post in this thread uses .apply rather than .call. The code at https://github.com/tc39/ecma402/issues/57#issuecomment-186856109 will need some adjustment to give these objects their own overriding .call and .apply methods without stomping on each other. But https://github.com/tc39/ecma402/issues/57#issuecomment-186856109 , if it otherwise works, gives the idea.
Andy VanWagoner
Comment 4 2016-02-21 11:46:24 PST
Ok, the gist is essentially that rather than try to swap the object in place, we let it be a proxy of sorts to a real Collator/NumberFormat/DateTimeFormat. I'll try this week to write a patch that does that. Thanks!
Andy VanWagoner
Comment 5 2016-02-27 16:19:10 PST
Darin Adler
Comment 6 2016-03-01 08:31:54 PST
Comment on attachment 272426 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=272426&action=review > Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:121 > + IntlDateTimeFormatConstructor* callee = jsCast<IntlDateTimeFormatConstructor*>(state->callee()); Since callee is used below and thisValue is not, I suggest moving this up one line and maybe initializing vm and callee in a separate paragraph. > Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:124 > + JSValue prototype = callee->getDirect(vm, vm.propertyNames->prototype); > + IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(thisValue); > + if (!dateTimeFormat && JSObject::defaultHasInstance(state, thisValue, prototype)) { We it would be nice to not do the work to get the prototype unless thisValue is not a dateTime, so we should be using two nested if statements here. First checking dateTimeFormat for null before getting the prototype. > Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:129 > + ASSERT(dateTimeFormat); This assertion seems a little excessive to me; not all that helpful. > Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:132 > + JSValue locales = state->argument(0); > + JSValue options = state->argument(1); > + dateTimeFormat->initializeDateTimeFormat(*state, locales, options); Not all that useful to put these into local variables; I’d suggest just writing this out in a single line. Same in the main code below. > Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:136 > + if (state->hadException()) > + return JSValue::encode(jsUndefined()); Where is this exception coming from? If it’s coming from the call to initializeDateTimeFormat, then I suggest doing it before calling putDirect. I am assuming that putDirect cannot return an exception. > Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:144 > // 3. ReturnIfAbrupt(dateTimeFormat). > ASSERT(dateTimeFormat); I’m a little mystified by this. The standard seems to contemplate an error case here that we assert does not exist! > Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp:118 > + // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns. All the same comments apply here as in the IntlDateTimeFormatConstructor.cpp file. It’s also bothering me that we are writing out separate copies of almost identical code for these two classes. Not great factoring.
Andy VanWagoner
Comment 7 2016-03-09 06:06:16 PST
Comment on attachment 272426 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=272426&action=review >> Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:121 >> + IntlDateTimeFormatConstructor* callee = jsCast<IntlDateTimeFormatConstructor*>(state->callee()); > > Since callee is used below and thisValue is not, I suggest moving this up one line and maybe initializing vm and callee in a separate paragraph. will do. >> Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:124 >> + if (!dateTimeFormat && JSObject::defaultHasInstance(state, thisValue, prototype)) { > > We it would be nice to not do the work to get the prototype unless thisValue is not a dateTime, so we should be using two nested if statements here. First checking dateTimeFormat for null before getting the prototype. will do. >> Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:129 >> + ASSERT(dateTimeFormat); > > This assertion seems a little excessive to me; not all that helpful. yeah, I'll pull it out, and the one below that also just asserts that create worked. >> Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:132 >> + dateTimeFormat->initializeDateTimeFormat(*state, locales, options); > > Not all that useful to put these into local variables; I’d suggest just writing this out in a single line. Same in the main code below. will do. >> Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:136 >> + return JSValue::encode(jsUndefined()); > > Where is this exception coming from? If it’s coming from the call to initializeDateTimeFormat, then I suggest doing it before calling putDirect. I am assuming that putDirect cannot return an exception. I assumed that putDirect can cause an exception on a sealed object. Is that not the case? >> Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp:118 >> + // FIXME: Workaround to provide compatibility with ECMA-402 1.0 call/apply patterns. > > All the same comments apply here as in the IntlDateTimeFormatConstructor.cpp file. It’s also bothering me that we are writing out separate copies of almost identical code for these two classes. Not great factoring. Personally, I think writing the same thing twice is better than trying to make an abstraction that makes sense and works in both places, especially when I expect this workaround to just get ripped out after a while. If it were 3 or 4 times, I would feel more pressure to create an abstraction.
Andy VanWagoner
Comment 8 2016-03-09 06:58:00 PST
Darin Adler
Comment 9 2016-03-09 20:37:30 PST
Comment on attachment 272426 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=272426&action=review >>> Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp:136 >>> + return JSValue::encode(jsUndefined()); >> >> Where is this exception coming from? If it’s coming from the call to initializeDateTimeFormat, then I suggest doing it before calling putDirect. I am assuming that putDirect cannot return an exception. > > I assumed that putDirect can cause an exception on a sealed object. Is that not the case? I do not think it can. I believe that putDirect is only safe to use when you know a sealed object is not involved.
WebKit Commit Bot
Comment 10 2016-03-09 21:28:23 PST
Comment on attachment 273426 [details] Patch Clearing flags on attachment: 273426 Committed r197925: <http://trac.webkit.org/changeset/197925>
WebKit Commit Bot
Comment 11 2016-03-09 21:28:26 PST
All reviewed patches have been landed. Closing bug.
Csaba Osztrogonác
Comment 13 2016-03-10 05:55:00 PST
(In reply to comment #12) > Looks like this caused 14 JSC tests to fail: > https://build.webkit.org/builders/ > Apple%20El%20Capitan%20Release%20JSC%20%28Tests%29/builds/4090/steps/jscore- > test/logs/stdio Please run run-javascriptcore-tests next time before landing a JSC change to avoid similar breakages.
Andy VanWagoner
Comment 14 2016-03-10 08:16:44 PST
(In reply to comment #13) > (In reply to comment #12) > > Looks like this caused 14 JSC tests to fail: > > https://build.webkit.org/builders/ > > Apple%20El%20Capitan%20Release%20JSC%20%28Tests%29/builds/4090/steps/jscore- > > test/logs/stdio > > Please run run-javascriptcore-tests next time before > landing a JSC change to avoid similar breakages. It's sad that this is not part of EWS.
Andy VanWagoner
Comment 15 2016-03-10 08:44:50 PST
shouldNotBe isn't defined in the test harness used by run-javascriptcore-tests, but is in the harness use by run-webkit-tests.
Csaba Osztrogonác
Comment 16 2016-03-10 08:53:12 PST
(In reply to comment #15) > shouldNotBe isn't defined in the test harness used by > run-javascriptcore-tests, but is in the harness use by run-webkit-tests. In this case you should add it to standalone-pre.js too.
Andy VanWagoner
Comment 17 2016-03-10 09:01:05 PST
(In reply to comment #16) > (In reply to comment #15) > > shouldNotBe isn't defined in the test harness used by > > run-javascriptcore-tests, but is in the harness use by run-webkit-tests. > > In this case you should add it to standalone-pre.js too. I'm preparing a patch now.
Andy VanWagoner
Comment 18 2016-03-10 09:39:05 PST
WebKit Commit Bot
Comment 19 2016-03-10 11:35:04 PST
Re-opened since this is blocked by bug 155308
Note You need to log in before you can comment on or make changes to this bug.