Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JSC] Implement Intl.DurationFormat #4589

Conversation

Constellation
Copy link
Member

@Constellation Constellation commented Sep 22, 2022

0a14082

[JSC] Implement Intl.DurationFormat
https://bugs.webkit.org/show_bug.cgi?id=214794
<rdar://66436701>

Reviewed by Ross Kirsling.

This patch implements Intl.DurationFormat[1], which is now stage-3 feature.
It is decoupled from Temporal now: it can take an object with `hours` etc. properties, and
generate formatted string for duration. In the future, it will accept Temporal.Duration too.

1. We add new microsecond and nanosecond units because they are necessary to DurationFormat[2].
2. Implement Intl.DurationFormat with UNumberFormatter and UListFormatter.

[1]: https://github.com/tc39/proposal-intl-duration-format
[2]: tc39/ecma402#708

* JSTests/stress/intl-durationformat-basic.js: Added.
(shouldBe):
(shouldBeOneOf):
(shouldBeForICUVersion):
(shouldNotThrow):
(shouldThrow):
* JSTests/stress/intl-durationformat-digital.js: Added.
(shouldBe):
(throw.new.Error):
* JSTests/stress/intl-durationformat-format-to-parts.js: Added.
(shouldBe):
(shouldBeOneOf):
(shouldBeForICUVersion):
(shouldNotThrow):
(shouldThrow):
(throw.new.Error):
* JSTests/stress/intl-durationformat.js: Added.
(shouldBe):
(shouldNotThrow):
(shouldThrow):
(test.DerivedDurationFormat):
(test.get shouldThrow):
(test):
* JSTests/stress/intl-enumeration.js:
* JSTests/test262/config.yaml:
* JSTests/test262/expectations.yaml:
* Source/JavaScriptCore/CMakeLists.txt:
* Source/JavaScriptCore/DerivedSources-input.xcfilelist:
* Source/JavaScriptCore/DerivedSources-output.xcfilelist:
* Source/JavaScriptCore/DerivedSources.make:
* Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj:
* Source/JavaScriptCore/Sources.txt:
* Source/JavaScriptCore/heap/Heap.cpp:
(JSC::Heap::Heap):
* Source/JavaScriptCore/heap/Heap.h:
* Source/JavaScriptCore/heap/HeapSubspaceTypes.h:
* Source/JavaScriptCore/runtime/CommonIdentifiers.h:
* Source/JavaScriptCore/runtime/IntlDurationFormat.cpp: Added.
(JSC::IntlDurationFormat::create):
(JSC::IntlDurationFormat::createStructure):
(JSC::IntlDurationFormat::IntlDurationFormat):
(JSC::IntlDurationFormat::finishCreation):
(JSC::intlDurationUnitOptions):
(JSC::displayName):
(JSC::IntlDurationFormat::initializeDurationFormat):
(JSC::ListFormatInput::ListFormatInput):
(JSC::ListFormatInput::size const):
(JSC::ListFormatInput::stringPointers const):
(JSC::ListFormatInput::stringLengths const):
(JSC::retrieveSeparator):
(JSC::collectElements):
(JSC::IntlDurationFormat::format const):
(JSC::IntlDurationFormat::formatToParts const):
(JSC::IntlDurationFormat::resolvedOptions const):
(JSC::IntlDurationFormat::styleString):
(JSC::IntlDurationFormat::unitStyleString):
(JSC::IntlDurationFormat::displayString):
* Source/JavaScriptCore/runtime/IntlDurationFormat.h: Added.
* Source/JavaScriptCore/runtime/IntlDurationFormatConstructor.cpp: Added.
(JSC::IntlDurationFormatConstructor::create):
(JSC::IntlDurationFormatConstructor::createStructure):
(JSC::IntlDurationFormatConstructor::IntlDurationFormatConstructor):
(JSC::IntlDurationFormatConstructor::finishCreation):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/IntlDurationFormatConstructor.h: Added.
* Source/JavaScriptCore/runtime/IntlDurationFormatPrototype.cpp: Added.
(JSC::IntlDurationFormatPrototype::create):
(JSC::IntlDurationFormatPrototype::createStructure):
(JSC::IntlDurationFormatPrototype::IntlDurationFormatPrototype):
(JSC::IntlDurationFormatPrototype::finishCreation):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/IntlDurationFormatPrototype.h: Added.
* Source/JavaScriptCore/runtime/IntlObject.cpp:
(JSC::createDurationFormatConstructor):
(JSC::IntlObject::finishCreation):
* Source/JavaScriptCore/runtime/IntlObject.h:
(JSC::intlDurationFormatAvailableLocales):
* Source/JavaScriptCore/runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::durationFormatStructure):

Canonical link: https://commits.webkit.org/254791@main

e71a4f8

Misc iOS, tvOS & watchOS macOS Linux Windows
❌ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 🧪 win
✅ 🛠 ios-sim 🛠 mac-debug ✅ 🛠 gtk ✅ 🛠 wincairo
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🛠 mac-AS-debug ✅ 🧪 gtk-wk2
✅ 🧪 api-ios ✅ 🧪 api-mac ✅ 🧪 api-gtk
✅ 🛠 🧪 jsc ✅ 🛠 tv 🧪 mac-wk1 ✅ 🛠 jsc-armv7
✅ 🛠 tv-sim ✅ 🧪 mac-wk2 ✅ 🧪 jsc-armv7-tests
🛠 🧪 merge ✅ 🛠 watch ✅ 🧪 mac-AS-debug-wk2 ✅ 🛠 jsc-mips
✅ 🛠 🧪 unsafe-merge ✅ 🛠 watch-sim ✅ 🧪 mac-wk2-stress ✅ 🧪 jsc-mips-tests

@Constellation Constellation requested a review from a team as a code owner September 22, 2022 08:03
@Constellation Constellation self-assigned this Sep 22, 2022
@Constellation Constellation added JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. WebKit Nightly Build labels Sep 22, 2022
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from fab2b91 to fc3ee47 Compare September 22, 2022 08:19
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from fc3ee47 to cfea900 Compare September 22, 2022 08:25
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Sep 22, 2022
@Constellation Constellation removed the merging-blocked Applied to prevent a change from being merged label Sep 22, 2022
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from cfea900 to 8515478 Compare September 22, 2022 08:48
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Sep 22, 2022
@Constellation Constellation removed the merging-blocked Applied to prevent a change from being merged label Sep 22, 2022
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from 8515478 to 5407f68 Compare September 22, 2022 15:23
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from 5407f68 to 3c368e2 Compare September 22, 2022 17:28
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from 3c368e2 to d2703af Compare September 22, 2022 19:06
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from d2703af to 4b4a4e0 Compare September 22, 2022 23:27
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from 4b4a4e0 to 6f72813 Compare September 23, 2022 00:47
@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from 6f72813 to 9b7d100 Compare September 23, 2022 03:14
Copy link
Member

@rkirsling rkirsling left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me with comments

Comment on lines +74 to +89
class UnitData {
public:
UnitData() = default;
UnitData(UnitStyle style, Display display)
: m_style(style)
, m_display(display)
{
}

UnitStyle style() const { return m_style; }
Display display() const { return m_display; }

private:
UnitStyle m_style : 7 { UnitStyle::Long };
Display m_display : 1 { Display::Always };
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just a struct?

Suggested change
class UnitData {
public:
UnitData() = default;
UnitData(UnitStyle style, Display display)
: m_style(style)
, m_display(display)
{
}
UnitStyle style() const { return m_style; }
Display display() const { return m_display; }
private:
UnitStyle m_style : 7 { UnitStyle::Long };
Display m_display : 1 { Display::Always };
};
struct UnitData {
UnitStyle style : 7 { UnitStyle::Long };
Display display : 1 { Display::Always };
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine. Changed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it causes some compile error.

/Users/yusukesuzuki/dev/OpenSource/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp:237:25: error: non-const reference cannot bind to bit-field 'm_style'
            prevStyle = unitData.m_style;

I'll just use the current class.

Comment on lines +114 to +122
// 1. Let availableLocales be %DurationFormat%.[[availableLocales]].
const auto& availableLocales = intlDurationFormatAvailableLocales();

// 2. Let requestedLocales be CanonicalizeLocaleList(locales).
Vector<String> requestedLocales = canonicalizeLocaleList(globalObject, callFrame->argument(0));
RETURN_IF_EXCEPTION(scope, encodedJSValue());

// 3. Return SupportedLocales(availableLocales, requestedLocales, options).
RELEASE_AND_RETURN(scope, JSValue::encode(supportedLocales(globalObject, availableLocales, requestedLocales, callFrame->argument(1))));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not really sure the step-by-step comments are helping in this case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is currently aligned to the rest of Intl code.

Comment on lines 112 to 113
IntlDurationFormat::UnitStyle style = styleValue.value_or(IntlDurationFormat::UnitStyle::Long);
if (!styleValue) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems weird to use value_or if we're guaranteed not to use the default value.

Suggested change
IntlDurationFormat::UnitStyle style = styleValue.value_or(IntlDurationFormat::UnitStyle::Long);
if (!styleValue) {
IntlDurationFormat::UnitStyle style;
if (styleValue)
style = styleValue.value();
else {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

Comment on lines 254 to +256
#if HAVE(ICU_U_LIST_FORMATTER)
if (Options::useIntlDurationFormat())
putDirectWithoutTransition(vm, vm.propertyNames->DurationFormat, createDurationFormatConstructor(vm, this), static_cast<unsigned>(PropertyAttribute::DontEnum));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems inconsistent that we're using #if HAVE(ICU_U_LIST_FORMATTER) to guard both specific places in the implementation and Intl.DurationFormat's whole existence.

I guess ListFormat is similar, but I think it's weird to design errors that can never be thrown.

Copy link
Member Author

@Constellation Constellation Sep 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is just for reducing compile time errors. We do not want to scatter this ifdefs outside of IntlDurationFormat.cpp as much as possible. So we confine them in that cpp file and this place by doing this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what I was thinking is that you could #if the whole IntlDurationFormat implementation instead of specific parts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes LUT table generation etc. hard to maintain on non-build platforms (and we need to put ifdefs in IntlDurationPrototype.cpp etc. too), so, this is avoiding that.

}

#if HAVE(ICU_U_LIST_FORMATTER)
class ListFormatInput {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not share this with IntlListFormat? It seems the same.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged.

@Constellation Constellation force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from 9b7d100 to e71a4f8 Compare September 23, 2022 04:55
@Constellation Constellation added 525.x (Safari 3.1) merge-queue Applied to send a pull request to merge-queue labels Sep 23, 2022
@webkit-ews-buildbot webkit-ews-buildbot added merging-blocked Applied to prevent a change from being merged and removed merge-queue Applied to send a pull request to merge-queue labels Sep 23, 2022
@Constellation Constellation added unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing and removed merging-blocked Applied to prevent a change from being merged labels Sep 23, 2022
@Constellation
Copy link
Member Author

The failure is unrelated flaky test

https://bugs.webkit.org/show_bug.cgi?id=214794
<rdar://66436701>

Reviewed by Ross Kirsling.

This patch implements Intl.DurationFormat[1], which is now stage-3 feature.
It is decoupled from Temporal now: it can take an object with `hours` etc. properties, and
generate formatted string for duration. In the future, it will accept Temporal.Duration too.

1. We add new microsecond and nanosecond units because they are necessary to DurationFormat[2].
2. Implement Intl.DurationFormat with UNumberFormatter and UListFormatter.

[1]: https://github.com/tc39/proposal-intl-duration-format
[2]: tc39/ecma402#708

* JSTests/stress/intl-durationformat-basic.js: Added.
(shouldBe):
(shouldBeOneOf):
(shouldBeForICUVersion):
(shouldNotThrow):
(shouldThrow):
* JSTests/stress/intl-durationformat-digital.js: Added.
(shouldBe):
(throw.new.Error):
* JSTests/stress/intl-durationformat-format-to-parts.js: Added.
(shouldBe):
(shouldBeOneOf):
(shouldBeForICUVersion):
(shouldNotThrow):
(shouldThrow):
(throw.new.Error):
* JSTests/stress/intl-durationformat.js: Added.
(shouldBe):
(shouldNotThrow):
(shouldThrow):
(test.DerivedDurationFormat):
(test.get shouldThrow):
(test):
* JSTests/stress/intl-enumeration.js:
* JSTests/test262/config.yaml:
* JSTests/test262/expectations.yaml:
* Source/JavaScriptCore/CMakeLists.txt:
* Source/JavaScriptCore/DerivedSources-input.xcfilelist:
* Source/JavaScriptCore/DerivedSources-output.xcfilelist:
* Source/JavaScriptCore/DerivedSources.make:
* Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj:
* Source/JavaScriptCore/Sources.txt:
* Source/JavaScriptCore/heap/Heap.cpp:
(JSC::Heap::Heap):
* Source/JavaScriptCore/heap/Heap.h:
* Source/JavaScriptCore/heap/HeapSubspaceTypes.h:
* Source/JavaScriptCore/runtime/CommonIdentifiers.h:
* Source/JavaScriptCore/runtime/IntlDurationFormat.cpp: Added.
(JSC::IntlDurationFormat::create):
(JSC::IntlDurationFormat::createStructure):
(JSC::IntlDurationFormat::IntlDurationFormat):
(JSC::IntlDurationFormat::finishCreation):
(JSC::intlDurationUnitOptions):
(JSC::displayName):
(JSC::IntlDurationFormat::initializeDurationFormat):
(JSC::ListFormatInput::ListFormatInput):
(JSC::ListFormatInput::size const):
(JSC::ListFormatInput::stringPointers const):
(JSC::ListFormatInput::stringLengths const):
(JSC::retrieveSeparator):
(JSC::collectElements):
(JSC::IntlDurationFormat::format const):
(JSC::IntlDurationFormat::formatToParts const):
(JSC::IntlDurationFormat::resolvedOptions const):
(JSC::IntlDurationFormat::styleString):
(JSC::IntlDurationFormat::unitStyleString):
(JSC::IntlDurationFormat::displayString):
* Source/JavaScriptCore/runtime/IntlDurationFormat.h: Added.
* Source/JavaScriptCore/runtime/IntlDurationFormatConstructor.cpp: Added.
(JSC::IntlDurationFormatConstructor::create):
(JSC::IntlDurationFormatConstructor::createStructure):
(JSC::IntlDurationFormatConstructor::IntlDurationFormatConstructor):
(JSC::IntlDurationFormatConstructor::finishCreation):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/IntlDurationFormatConstructor.h: Added.
* Source/JavaScriptCore/runtime/IntlDurationFormatPrototype.cpp: Added.
(JSC::IntlDurationFormatPrototype::create):
(JSC::IntlDurationFormatPrototype::createStructure):
(JSC::IntlDurationFormatPrototype::IntlDurationFormatPrototype):
(JSC::IntlDurationFormatPrototype::finishCreation):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/IntlDurationFormatPrototype.h: Added.
* Source/JavaScriptCore/runtime/IntlObject.cpp:
(JSC::createDurationFormatConstructor):
(JSC::IntlObject::finishCreation):
* Source/JavaScriptCore/runtime/IntlObject.h:
(JSC::intlDurationFormatAvailableLocales):
* Source/JavaScriptCore/runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* Source/JavaScriptCore/runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::durationFormatStructure):

Canonical link: https://commits.webkit.org/254791@main
@webkit-early-warning-system webkit-early-warning-system force-pushed the eng/JSC-Implement-Intl-DurationFormat branch from e71a4f8 to 0a14082 Compare September 23, 2022 16:26
@webkit-commit-queue
Copy link
Collaborator

Committed 254791@main (0a14082): https://commits.webkit.org/254791@main

Reviewed commits have been landed. Closing PR #4589 and removing active labels.

@webkit-early-warning-system webkit-early-warning-system merged commit 0a14082 into WebKit:main Sep 23, 2022
@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Sep 23, 2022
@Constellation Constellation deleted the eng/JSC-Implement-Intl-DurationFormat branch September 23, 2022 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants