Changeset 281838 in webkit


Ignore:
Timestamp:
Aug 31, 2021 10:24:30 PM (11 months ago)
Author:
Ross Kirsling
Message:

[JSC] Implement Temporal.Duration
https://bugs.webkit.org/show_bug.cgi?id=228532

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/temporal-duration.js: Added.
  • test262/config.yaml: Enabled Duration tests.

Source/JavaScriptCore:

This patch implements the Duration class for the upcoming Temporal API (currently at stage 3 in TC39).
Spec: https://tc39.es/proposal-temporal/#sec-temporal-duration-objects
Docs: https://tc39.es/proposal-temporal/docs/duration.html

A Duration is ultimately an array of doubles (years, months, weeks, days, hours, minutes, seconds, ms, μs, ns)
which can be converted to and from an ISO string representation (e.g. "-P1Y2M3W4DT5H6M7.123456789S")
and which supports various calculations.

The spec is still in flux and certain issues were identified in the course of preparing this patch.
This code aims to be "as correct as possible" for the moment; small corrections are expected in the near future.

  • CMakeLists.txt:
  • DerivedSources.make:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • runtime/CommonIdentifiers.h:
  • runtime/ISO8601.cpp: Added.
  • runtime/ISO8601.h: Added.
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildrenImpl):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::durationStructure):

  • runtime/TemporalDuration.cpp: Added.
  • runtime/TemporalDuration.h: Added.
  • runtime/TemporalDurationConstructor.cpp: Added.
  • runtime/TemporalDurationConstructor.h: Added.
  • runtime/TemporalDurationPrototype.cpp: Added.
  • runtime/TemporalDurationPrototype.h: Added.
  • runtime/TemporalObject.cpp:

(JSC::createDurationConstructor):
(JSC::singularUnit):
(JSC::temporalUnitType):
(JSC::temporalLargestUnit):
(JSC::temporalSmallestUnit):
(JSC::temporalFractionalSecondDigits):
(JSC::secondsStringPrecision):
(JSC::maximumRoundingIncrement):
(JSC::temporalRoundingIncrement):
(JSC::roundNumberToIncrement):

  • runtime/TemporalObject.h:
  • runtime/VM.cpp:
  • runtime/VM.h:
Location:
trunk
Files:
9 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r281789 r281838  
     12021-08-31  Ross Kirsling  <ross.kirsling@sony.com>
     2
     3        [JSC] Implement Temporal.Duration
     4        https://bugs.webkit.org/show_bug.cgi?id=228532
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        * stress/temporal-duration.js: Added.
     9        * test262/config.yaml: Enabled Duration tests.
     10
    1112021-08-30  Ross Kirsling  <ross.kirsling@sony.com>
    212
  • trunk/JSTests/test262/config.yaml

    r281799 r281838  
    77  TypedArray.prototype.at: useAtMethod
    88  String.prototype.at: useAtMethod
     9  Temporal: useTemporal
    910  array-find-from-last: useArrayFindLastMethod
    1011  Object.hasOwn: useHasOwn
     
    1617    - cleanupSome
    1718    - resizable-arraybuffer
    18     - Temporal
    1919    - import-assertions
    2020    - json-modules
     
    2222    - callable-boundary-realms
    2323  paths:
     24    - test/built-ins/Temporal/Calendar
     25    - test/built-ins/Temporal/Instant
     26    - test/built-ins/Temporal/Now
     27    - test/built-ins/Temporal/PlainDate
     28    - test/built-ins/Temporal/PlainDateTime
     29    - test/built-ins/Temporal/PlainMonthDay
     30    - test/built-ins/Temporal/PlainTime
     31    - test/built-ins/Temporal/PlainYearMonth
     32    - test/built-ins/Temporal/TimeZone
     33    - test/built-ins/Temporal/ZonedDateTime
    2434  files:
    2535    # https://github.com/claudepache/es-legacy-function-reflection
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r281788 r281838  
    110110    runtime/TemporalCalendarConstructor.cpp
    111111    runtime/TemporalCalendarPrototype.cpp
     112    runtime/TemporalDurationConstructor.cpp
     113    runtime/TemporalDurationPrototype.cpp
    112114    runtime/TemporalObject.cpp
    113115
  • trunk/Source/JavaScriptCore/ChangeLog

    r281837 r281838  
     12021-08-31  Ross Kirsling  <ross.kirsling@sony.com>
     2
     3        [JSC] Implement Temporal.Duration
     4        https://bugs.webkit.org/show_bug.cgi?id=228532
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        This patch implements the Duration class for the upcoming Temporal API (currently at stage 3 in TC39).
     9        Spec: https://tc39.es/proposal-temporal/#sec-temporal-duration-objects
     10        Docs: https://tc39.es/proposal-temporal/docs/duration.html
     11
     12        A Duration is ultimately an array of doubles (years, months, weeks, days, hours, minutes, seconds, ms, μs, ns)
     13        which can be converted to and from an ISO string representation (e.g. "-P1Y2M3W4DT5H6M7.123456789S")
     14        and which supports various calculations.
     15
     16        The spec is still in flux and certain issues were identified in the course of preparing this patch.
     17        This code aims to be "as correct as possible" for the moment; small corrections are expected in the near future.
     18
     19        * CMakeLists.txt:
     20        * DerivedSources.make:
     21        * JavaScriptCore.xcodeproj/project.pbxproj:
     22        * Sources.txt:
     23        * runtime/CommonIdentifiers.h:
     24        * runtime/ISO8601.cpp: Added.
     25        * runtime/ISO8601.h: Added.
     26        * runtime/JSGlobalObject.cpp:
     27        (JSC::JSGlobalObject::init):
     28        (JSC::JSGlobalObject::visitChildrenImpl):
     29        * runtime/JSGlobalObject.h:
     30        (JSC::JSGlobalObject::durationStructure):
     31        * runtime/TemporalDuration.cpp: Added.
     32        * runtime/TemporalDuration.h: Added.
     33        * runtime/TemporalDurationConstructor.cpp: Added.
     34        * runtime/TemporalDurationConstructor.h: Added.
     35        * runtime/TemporalDurationPrototype.cpp: Added.
     36        * runtime/TemporalDurationPrototype.h: Added.
     37        * runtime/TemporalObject.cpp:
     38        (JSC::createDurationConstructor):
     39        (JSC::singularUnit):
     40        (JSC::temporalUnitType):
     41        (JSC::temporalLargestUnit):
     42        (JSC::temporalSmallestUnit):
     43        (JSC::temporalFractionalSecondDigits):
     44        (JSC::secondsStringPrecision):
     45        (JSC::maximumRoundingIncrement):
     46        (JSC::temporalRoundingIncrement):
     47        (JSC::roundNumberToIncrement):
     48        * runtime/TemporalObject.h:
     49        * runtime/VM.cpp:
     50        * runtime/VM.h:
     51
    1522021-08-31  Lauro Moura  <lmoura@igalia.com>
    253
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r281788 r281838  
    194194    TemporalCalendarConstructor.lut.h \
    195195    TemporalCalendarPrototype.lut.h \
     196    TemporalDurationConstructor.lut.h \
     197    TemporalDurationPrototype.lut.h \
    196198    TemporalObject.lut.h \
    197199    WebAssemblyCompileErrorConstructor.lut.h \
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r281788 r281838  
    14141414                A321AA6D2626359B0023ADA2 /* IntlWorkaround.h in Headers */ = {isa = PBXBuildFile; fileRef = A321AA6C2626359B0023ADA2 /* IntlWorkaround.h */; };
    14151415                A382C5312667111D0042CD99 /* InByVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = E3305FB120B0F78800CEB82B /* InByVariant.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1416                A38CA59E26DD84DE00C8D84C /* ISO8601.h in Headers */ = {isa = PBXBuildFile; fileRef = A38CA59C26DD84DE00C8D84C /* ISO8601.h */; };
    14161417                A38D250E25800D440042BFDD /* JSArrayBufferPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A38D250D25800D430042BFDD /* JSArrayBufferPrototypeInlines.h */; };
    14171418                A38D5BFC2666D3DA00A109A6 /* InByStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = A38D5BFA2666D3DA00A109A6 /* InByStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
    14181419                A3EE8543262514B000FC9B8D /* IntlWorkaround.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A37619402625127C00CBCBA9 /* IntlWorkaround.cpp */; };
     1420                A3C7EDB626B0DB38004C34C5 /* TemporalDurationPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A3C7EDB026B0DB36004C34C5 /* TemporalDurationPrototype.h */; };
     1421                A3C7EDB926B0DB38004C34C5 /* TemporalDuration.h in Headers */ = {isa = PBXBuildFile; fileRef = A3C7EDB326B0DB37004C34C5 /* TemporalDuration.h */; };
     1422                A3C7EDBA26B0DB38004C34C5 /* TemporalDurationConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A3C7EDB426B0DB37004C34C5 /* TemporalDurationConstructor.h */; };
    14191423                A3FF9BC72234749100B1A9AB /* YarrFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = A3FF9BC52234746600B1A9AB /* YarrFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
    14201424                A503FA1A188E0FB000110F14 /* JavaScriptCallFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */; };
     
    44624466                A321AA6C2626359B0023ADA2 /* IntlWorkaround.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlWorkaround.h; sourceTree = "<group>"; };
    44634467                A37619402625127C00CBCBA9 /* IntlWorkaround.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlWorkaround.cpp; sourceTree = "<group>"; };
     4468                A38CA59B26DD84DE00C8D84C /* ISO8601.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ISO8601.cpp; sourceTree = "<group>"; };
     4469                A38CA59C26DD84DE00C8D84C /* ISO8601.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601.h; sourceTree = "<group>"; };
    44644470                A38D250D25800D430042BFDD /* JSArrayBufferPrototypeInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSArrayBufferPrototypeInlines.h; sourceTree = "<group>"; };
    44654471                A38D5BF92666D3DA00A109A6 /* InByStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InByStatus.cpp; sourceTree = "<group>"; };
     
    44774483                A3BF884F24480BE0001B9F35 /* IntlRelativeTimeFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormat.cpp; sourceTree = "<group>"; };
    44784484                A3BF885024480BE1001B9F35 /* IntlRelativeTimeFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormat.h; sourceTree = "<group>"; };
     4485                A3C7EDB026B0DB36004C34C5 /* TemporalDurationPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemporalDurationPrototype.h; sourceTree = "<group>"; };
     4486                A3C7EDB126B0DB36004C34C5 /* TemporalDuration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalDuration.cpp; sourceTree = "<group>"; };
     4487                A3C7EDB226B0DB37004C34C5 /* TemporalDurationConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalDurationConstructor.cpp; sourceTree = "<group>"; };
     4488                A3C7EDB326B0DB37004C34C5 /* TemporalDuration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemporalDuration.h; sourceTree = "<group>"; };
     4489                A3C7EDB426B0DB37004C34C5 /* TemporalDurationConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemporalDurationConstructor.h; sourceTree = "<group>"; };
     4490                A3C7EDB526B0DB37004C34C5 /* TemporalDurationPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalDurationPrototype.cpp; sourceTree = "<group>"; };
    44794491                A3FF9BC52234746600B1A9AB /* YarrFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrFlags.h; path = yarr/YarrFlags.h; sourceTree = "<group>"; };
    44804492                A3FF9BC62234746600B1A9AB /* YarrFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrFlags.cpp; path = yarr/YarrFlags.cpp; sourceTree = "<group>"; };
     
    75777589                                0F275F2C1ECE079600620D47 /* Intrinsic.cpp */,
    75787590                                86BF642A148DB2B5004DE36A /* Intrinsic.h */,
     7591                                A38CA59B26DD84DE00C8D84C /* ISO8601.cpp */,
     7592                                A38CA59C26DD84DE00C8D84C /* ISO8601.h */,
    75797593                                8B9F6D551D5912FA001C739F /* IterationKind.h */,
    75807594                                FE4D55B71AE716CA0052E459 /* IterationStatus.h */,
     
    79757989                                E32D4DE226DAFD4200D4533A /* TemporalCalendarPrototype.cpp */,
    79767990                                E32D4DE126DAFD4200D4533A /* TemporalCalendarPrototype.h */,
     7991                                A3C7EDB126B0DB36004C34C5 /* TemporalDuration.cpp */,
     7992                                A3C7EDB326B0DB37004C34C5 /* TemporalDuration.h */,
     7993                                A3C7EDB226B0DB37004C34C5 /* TemporalDurationConstructor.cpp */,
     7994                                A3C7EDB426B0DB37004C34C5 /* TemporalDurationConstructor.h */,
     7995                                A3C7EDB526B0DB37004C34C5 /* TemporalDurationPrototype.cpp */,
     7996                                A3C7EDB026B0DB36004C34C5 /* TemporalDurationPrototype.h */,
    79777997                                F6F1501B2693D33E004B98EF /* TemporalNow.cpp */,
    79787998                                F6F150182693D33D004B98EF /* TemporalNow.h */,
     
    1009510115                                860BD801148EA6F200112B2F /* Intrinsic.h in Headers */,
    1009610116                                534E03541E53BD2900213F64 /* IntrinsicGetterAccessCase.h in Headers */,
     10117                                A38CA59E26DD84DE00C8D84C /* ISO8601.h in Headers */,
    1009710118                                0FDCE1321FB11DA4006F3901 /* IsoAlignedMemoryAllocator.h in Headers */,
    1009810119                                0FB467801FDDA6F1003FCB09 /* IsoCellSet.h in Headers */,
     
    1067610697                                E32D4DE726DAFD4300D4533A /* TemporalCalendarPrototype.h in Headers */,
    1067710698                                E39DA1DA26DB5E4C00100437 /* TemporalCalendarPrototype.lut.h in Headers */,
     10699                                A3C7EDB926B0DB38004C34C5 /* TemporalDuration.h in Headers */,
     10700                                A3C7EDBA26B0DB38004C34C5 /* TemporalDurationConstructor.h in Headers */,
     10701                                A3C7EDB626B0DB38004C34C5 /* TemporalDurationPrototype.h in Headers */,
    1067810702                                F6F150212693D450004B98EF /* TemporalObject.lut.h in Headers */,
    1067910703                                0F24E54F17EE274900ABB217 /* TempRegisterSet.h in Headers */,
  • trunk/Source/JavaScriptCore/Sources.txt

    r281788 r281838  
    854854runtime/IntlSegmentsPrototype.cpp
    855855runtime/IntlWorkaround.cpp @no-unify // Confine U_HIDE_DRAFT_API's effect to this file.
     856runtime/ISO8601.cpp
    856857runtime/IteratorOperations.cpp
    857858runtime/IteratorPrototype.cpp
     
    10141015runtime/TemporalCalendarConstructor.cpp
    10151016runtime/TemporalCalendarPrototype.cpp
     1017runtime/TemporalDuration.cpp
     1018runtime/TemporalDurationConstructor.cpp
     1019runtime/TemporalDurationPrototype.cpp
    10161020runtime/TemporalNow.cpp
    10171021runtime/TemporalObject.cpp
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r281799 r281838  
    100100    macro(dateStyle) \
    101101    macro(day) \
     102    macro(days) \
    102103    macro(dayPeriod) \
    103104    macro(defineProperty) \
     
    139140    macro(header) \
    140141    macro(hour) \
     142    macro(hours) \
    141143    macro(hourCycle) \
    142144    macro(hour12) \
     
    159161    macro(language) \
    160162    macro(languageDisplay) \
     163    macro(largestUnit) \
    161164    macro(lastIndex) \
    162165    macro(length) \
     
    167170    macro(maximumSignificantDigits) \
    168171    macro(message) \
     172    macro(microseconds) \
     173    macro(milliseconds) \
    169174    macro(minimumFractionDigits) \
    170175    macro(minimumIntegerDigits) \
    171176    macro(minimumSignificantDigits) \
    172177    macro(minute) \
     178    macro(minutes) \
    173179    macro(month) \
    174180    macro(monthCode) \
     181    macro(months) \
    175182    macro(multiline) \
    176183    macro(name) \
     184    macro(nanoseconds) \
    177185    macro(next) \
    178186    macro(now) \
     
    197205    macro(replace) \
    198206    macro(resolve) \
     207    macro(roundingIncrement) \
     208    macro(roundingMode) \
    199209    macro(script) \
    200210    macro(second) \
     211    macro(seconds) \
    201212    macro(segment) \
    202213    macro(sensitivity) \
     
    204215    macro(size) \
    205216    macro(slice) \
     217    macro(smallestUnit) \
    206218    macro(source) \
    207219    macro(sourceCode) \
     
    230242    macro(uid) \
    231243    macro(unicode) \
     244    macro(unit) \
    232245    macro(usage) \
    233246    macro(value) \
    234247    macro(valueOf) \
    235248    macro(weekday) \
     249    macro(weeks) \
    236250    macro(writable) \
    237     macro(year)
     251    macro(year) \
     252    macro(years)
    238253
    239254#define JSC_COMMON_IDENTIFIERS_EACH_PRIVATE_FIELD(macro) \
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r281788 r281838  
    203203#include "SymbolPrototype.h"
    204204#include "TemporalCalendar.h"
    205 #include "TemporalCalendarConstructor.h"
    206205#include "TemporalCalendarPrototype.h"
     206#include "TemporalDuration.h"
     207#include "TemporalDurationPrototype.h"
    207208#include "TemporalObject.h"
    208209#include "VMTrapsInlines.h"
     
    12211222                TemporalCalendarPrototype* calendarPrototype = TemporalCalendarPrototype::create(init.vm, globalObject, TemporalCalendarPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
    12221223                init.set(TemporalCalendar::createStructure(init.vm, globalObject, calendarPrototype));
     1224            });
     1225
     1226        m_durationStructure.initLater(
     1227            [] (const Initializer<Structure>& init) {
     1228                JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
     1229                TemporalDurationPrototype* durationPrototype = TemporalDurationPrototype::create(init.vm, TemporalDurationPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
     1230                init.set(TemporalDuration::createStructure(init.vm, globalObject, durationPrototype));
    12231231            });
    12241232
     
    21022110
    21032111    thisObject->m_calendarStructure.visit(visitor);
     2112    thisObject->m_durationStructure.visit(visitor);
    21042113
    21052114    visitor.append(thisObject->m_nullGetterFunction);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r281788 r281838  
    326326
    327327    LazyProperty<JSGlobalObject, Structure> m_calendarStructure;
     328    LazyProperty<JSGlobalObject, Structure> m_durationStructure;
    328329
    329330    WriteBarrier<NullGetterFunction> m_nullGetterFunction;
     
    874875
    875876    Structure* calendarStructure() { return m_calendarStructure.get(this); }
     877    Structure* durationStructure() { return m_durationStructure.get(this); }
    876878
    877879    JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);
  • trunk/Source/JavaScriptCore/runtime/TemporalObject.cpp

    r281788 r281838  
    22 *  Copyright (C) 2021 Igalia S.L. All rights reserved.
    33 *  Copyright (C) 2021 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2021 Sony Interactive Entertainment Inc.
    45 *
    56 *  This library is free software; you can redistribute it and/or
     
    2324
    2425#include "FunctionPrototype.h"
     26#include "IntlObjectInlines.h"
    2527#include "JSCJSValueInlines.h"
    2628#include "JSGlobalObject.h"
     
    2931#include "TemporalCalendarConstructor.h"
    3032#include "TemporalCalendarPrototype.h"
     33#include "TemporalDurationConstructor.h"
     34#include "TemporalDurationPrototype.h"
    3135#include "TemporalNow.h"
    3236
     
    4751    JSGlobalObject* globalObject = temporalObject->globalObject(vm);
    4852    return TemporalNow::create(vm, TemporalNow::createStructure(vm, globalObject));
     53}
     54
     55static JSValue createDurationConstructor(VM& vm, JSObject* object)
     56{
     57    TemporalObject* temporalObject = jsCast<TemporalObject*>(object);
     58    JSGlobalObject* globalObject = temporalObject->globalObject(vm);
     59    return TemporalDurationConstructor::create(vm, TemporalDurationConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<TemporalDurationPrototype*>(globalObject->durationStructure()->storedPrototypeObject()));
    4960}
    5061
     
    5970  Calendar       createCalendarConstructor       DontEnum|PropertyCallback
    6071  Now            createNowObject                 DontEnum|PropertyCallback
     72  Duration       createDurationConstructor       DontEnum|PropertyCallback
    6173@end
    6274*/
     
    88100}
    89101
     102static StringView singularUnit(StringView unit)
     103{
     104    // Plurals are allowed, but thankfully they're all just a simple -s.
     105    return unit.endsWith("s") ? unit.left(unit.length() - 1) : unit;
     106}
     107
     108std::optional<TemporalUnit> temporalUnitType(StringView unit)
     109{
     110    StringView singular = singularUnit(unit);
     111
     112    if (singular == "year")
     113        return TemporalUnit::Year;
     114    if (singular == "month")
     115        return TemporalUnit::Month;
     116    if (singular == "week")
     117        return TemporalUnit::Week;
     118    if (singular == "day")
     119        return TemporalUnit::Day;
     120    if (singular == "hour")
     121        return TemporalUnit::Hour;
     122    if (singular == "minute")
     123        return TemporalUnit::Minute;
     124    if (singular == "second")
     125        return TemporalUnit::Second;
     126    if (singular == "millisecond")
     127        return TemporalUnit::Millisecond;
     128    if (singular == "microsecond")
     129        return TemporalUnit::Microsecond;
     130    if (singular == "nanosecond")
     131        return TemporalUnit::Nanosecond;
     132   
     133    return std::nullopt;
     134}
     135
     136// ToLargestTemporalUnit ( normalizedOptions, disallowedUnits, fallback [ , autoValue ] )
     137// https://tc39.es/proposal-temporal/#sec-temporal-tolargesttemporalunit
     138std::optional<TemporalUnit> temporalLargestUnit(JSGlobalObject* globalObject, JSObject* options, std::initializer_list<TemporalUnit> disallowedUnits, TemporalUnit autoValue)
     139{
     140    VM& vm = globalObject->vm();
     141    auto scope = DECLARE_THROW_SCOPE(vm);
     142
     143    String largestUnit = intlStringOption(globalObject, options, vm.propertyNames->largestUnit, { }, nullptr, nullptr);
     144    RETURN_IF_EXCEPTION(scope, std::nullopt);
     145
     146    if (!largestUnit)
     147        return std::nullopt;
     148
     149    if (largestUnit == "auto"_s)
     150        return autoValue;
     151
     152    auto unitType = temporalUnitType(largestUnit);
     153    if (!unitType) {
     154        throwRangeError(globalObject, scope, "largestUnit is an invalid Temporal unit"_s);
     155        return std::nullopt;
     156    }
     157
     158    if (disallowedUnits.size() && std::find(disallowedUnits.begin(), disallowedUnits.end(), unitType.value()) != disallowedUnits.end()) {
     159        throwRangeError(globalObject, scope, "largestUnit is a disallowed unit"_s);
     160        return std::nullopt;
     161    }
     162
     163    return unitType;
     164}
     165
     166// ToSmallestTemporalUnit ( normalizedOptions, disallowedUnits, fallback )
     167// https://tc39.es/proposal-temporal/#sec-temporal-tosmallesttemporalunit
     168std::optional<TemporalUnit> temporalSmallestUnit(JSGlobalObject* globalObject, JSObject* options, std::initializer_list<TemporalUnit> disallowedUnits)
     169{
     170    VM& vm = globalObject->vm();
     171    auto scope = DECLARE_THROW_SCOPE(vm);
     172
     173    String smallestUnit = intlStringOption(globalObject, options, vm.propertyNames->smallestUnit, { }, nullptr, nullptr);
     174    RETURN_IF_EXCEPTION(scope, std::nullopt);
     175
     176    if (!smallestUnit)
     177        return std::nullopt;
     178
     179    auto unitType = temporalUnitType(smallestUnit);
     180    if (!unitType) {
     181        throwRangeError(globalObject, scope, "smallestUnit is an invalid Temporal unit"_s);
     182        return std::nullopt;
     183    }
     184
     185    if (disallowedUnits.size() && std::find(disallowedUnits.begin(), disallowedUnits.end(), unitType.value()) != disallowedUnits.end()) {
     186        throwRangeError(globalObject, scope, "smallestUnit is a disallowed unit"_s);
     187        return std::nullopt;
     188    }
     189
     190    return unitType;
     191}
     192
     193// GetStringOrNumberOption(normalizedOptions, "fractionalSecondDigits", « "auto" », 0, 9, "auto")
     194// https://tc39.es/proposal-temporal/#sec-getstringornumberoption
     195std::optional<unsigned> temporalFractionalSecondDigits(JSGlobalObject* globalObject, JSObject* options)
     196{
     197    VM& vm = globalObject->vm();
     198    auto scope = DECLARE_THROW_SCOPE(vm);
     199
     200    if (!options)
     201        return std::nullopt;
     202
     203    JSValue value = options->get(globalObject, vm.propertyNames->fractionalSecondDigits);
     204    RETURN_IF_EXCEPTION(scope, std::nullopt);
     205
     206    if (value.isUndefined())
     207        return std::nullopt;
     208
     209    if (value.isNumber()) {
     210        double doubleValue = value.asNumber();
     211        if (doubleValue < 0 || doubleValue > 9) {
     212            throwRangeError(globalObject, scope, "fractionalSecondDigits is out of range"_s);
     213            return std::nullopt;
     214        }
     215
     216        return static_cast<unsigned>(doubleValue);
     217    }
     218
     219    String stringValue = value.toWTFString(globalObject);
     220    RETURN_IF_EXCEPTION(scope, std::nullopt);
     221
     222    if (stringValue != "auto")
     223        throwRangeError(globalObject, scope, "fractionalSecondDigits is out of range"_s);
     224
     225    return std::nullopt;
     226}
     227
     228// ToSecondsStringPrecision ( normalizedOptions )
     229// https://tc39.es/proposal-temporal/#sec-temporal-tosecondsstringprecision
     230PrecisionData secondsStringPrecision(JSGlobalObject* globalObject, JSObject* options)
     231{
     232    VM& vm = globalObject->vm();
     233    auto scope = DECLARE_THROW_SCOPE(vm);
     234
     235    auto smallestUnit = temporalSmallestUnit(globalObject, options, { TemporalUnit::Year, TemporalUnit::Month, TemporalUnit::Week, TemporalUnit::Day, TemporalUnit::Hour, TemporalUnit::Minute });
     236    RETURN_IF_EXCEPTION(scope, { });
     237
     238    if (smallestUnit) {
     239        switch (smallestUnit.value()) {
     240        case TemporalUnit::Second:
     241            return { 0, TemporalUnit::Second, 1 };
     242        case TemporalUnit::Millisecond:
     243            return { 3, TemporalUnit::Millisecond, 1 };
     244        case TemporalUnit::Microsecond:
     245            return { 6, TemporalUnit::Microsecond, 1 };
     246        case TemporalUnit::Nanosecond:
     247            return { 9, TemporalUnit::Nanosecond, 1 };
     248        default:
     249            RELEASE_ASSERT_NOT_REACHED();
     250            return { };
     251        }
     252    }
     253
     254    auto precision = temporalFractionalSecondDigits(globalObject, options);
     255    RETURN_IF_EXCEPTION(scope, { });
     256
     257    if (!precision)
     258        return { std::nullopt, TemporalUnit::Nanosecond, 1 };
     259
     260    unsigned digits = precision.value();
     261    if (!digits)
     262        return { 0, TemporalUnit::Second, 1 };
     263
     264    if (digits <= 3)
     265        return { digits, TemporalUnit::Millisecond, std::pow(10, 3 - digits) };
     266
     267    if (digits <= 6)
     268        return { digits, TemporalUnit::Microsecond, std::pow(10, 6 - digits) };
     269
     270    ASSERT(digits <= 9);
     271    return { digits, TemporalUnit::Nanosecond, std::pow(10, 9 - digits) };
     272}
     273
     274// MaximumTemporalDurationRoundingIncrement ( unit )
     275// https://tc39.es/proposal-temporal/#sec-temporal-maximumtemporaldurationroundingincrement
     276std::optional<double> maximumRoundingIncrement(TemporalUnit unit)
     277{
     278    if (unit <= TemporalUnit::Day)
     279        return std::nullopt;
     280    if (unit == TemporalUnit::Hour)
     281        return 24;
     282    if (unit <= TemporalUnit::Second)
     283        return 60;
     284    return 1000;
     285}
     286
     287// ToTemporalRoundingIncrement ( normalizedOptions, dividend, inclusive )
     288// https://tc39.es/proposal-temporal/#sec-temporal-totemporalroundingincrement
     289double temporalRoundingIncrement(JSGlobalObject* globalObject, JSObject* options, std::optional<double> dividend, bool inclusive)
     290{
     291    VM& vm = globalObject->vm();
     292    auto scope = DECLARE_THROW_SCOPE(vm);
     293
     294    double maximum;
     295    if (!dividend)
     296        maximum = std::numeric_limits<double>::infinity();
     297    else if (inclusive)
     298        maximum = dividend.value();
     299    else if (dividend.value() > 1)
     300        maximum = dividend.value() - 1;
     301    else
     302        maximum = 1;
     303
     304    double increment = intlNumberOption(globalObject, options, vm.propertyNames->roundingIncrement, 1, maximum, 1);
     305    RETURN_IF_EXCEPTION(scope, 0);
     306
     307    increment = std::floor(increment);
     308    if (dividend && std::fmod(dividend.value(), increment)) {
     309        throwRangeError(globalObject, scope, makeString("roundingIncrement value does not divide "_s, dividend.value(), " evenly"_s));
     310        return 0;
     311    }
     312
     313    return increment;
     314}
     315
     316// RoundNumberToIncrement ( x, increment, roundingMode )
     317// https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
     318double roundNumberToIncrement(double x, double increment, RoundingMode mode)
     319{
     320    auto quotient = x / increment;
     321    switch (mode) {
     322    case RoundingMode::Ceil:
     323        return -std::floor(-quotient) * increment;
     324    case RoundingMode::Floor:
     325        return std::floor(quotient) * increment;
     326    case RoundingMode::Trunc:
     327        return std::trunc(quotient) * increment;
     328    case RoundingMode::HalfExpand:
     329        return std::round(quotient) * increment;
     330    }
     331}
     332
    90333} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/TemporalObject.h

    r279630 r281838  
    11/*
    22 *  Copyright (C) 2021 Igalia, S.L. All rights reserved.
     3 *  Copyright (C) 2021 Sony Interactive Entertainment Inc.
    34 *
    45 *  This library is free software; you can redistribute it and/or
     
    2425namespace JSC {
    2526
     27#define JSC_TEMPORAL_UNITS(macro) \
     28    macro(year, Year) \
     29    macro(month, Month) \
     30    macro(week, Week) \
     31    macro(day, Day) \
     32    macro(hour, Hour) \
     33    macro(minute, Minute) \
     34    macro(second, Second) \
     35    macro(millisecond, Millisecond) \
     36    macro(microsecond, Microsecond) \
     37    macro(nanosecond, Nanosecond) \
     38
     39enum class TemporalUnit : uint8_t {
     40#define JSC_DEFINE_TEMPORAL_UNIT_ENUM(name, capitalizedName) capitalizedName,
     41    JSC_TEMPORAL_UNITS(JSC_DEFINE_TEMPORAL_UNIT_ENUM)
     42#undef JSC_DEFINE_TEMPORAL_UNIT_ENUM
     43};
     44#define JSC_COUNT_TEMPORAL_UNITS(name, capitalizedName) + 1
     45static constexpr unsigned numberOfTemporalUnits = 0 JSC_TEMPORAL_UNITS(JSC_COUNT_TEMPORAL_UNITS);
     46#undef JSC_COUNT_TEMPORAL_UNITS
     47
    2648class TemporalObject final : public JSNonFinalObject {
    2749public:
     
    4668};
    4769
     70enum class RoundingMode : uint8_t {
     71    Ceil,
     72    Floor,
     73    Trunc,
     74    HalfExpand
     75};
     76
     77struct PrecisionData {
     78    std::optional<unsigned> precision;
     79    TemporalUnit unit;
     80    double increment;
     81};
     82
     83std::optional<TemporalUnit> temporalUnitType(StringView);
     84std::optional<TemporalUnit> temporalLargestUnit(JSGlobalObject*, JSObject* options, std::initializer_list<TemporalUnit> disallowedUnits, TemporalUnit autoValue);
     85std::optional<TemporalUnit> temporalSmallestUnit(JSGlobalObject*, JSObject* options, std::initializer_list<TemporalUnit> disallowedUnits);
     86std::optional<unsigned> temporalFractionalSecondDigits(JSGlobalObject*, JSObject* options);
     87PrecisionData secondsStringPrecision(JSGlobalObject*, JSObject* options);
     88std::optional<double> maximumRoundingIncrement(TemporalUnit);
     89double temporalRoundingIncrement(JSGlobalObject*, JSObject* options, std::optional<double> dividend, bool inclusive);
     90double roundNumberToIncrement(double, double increment, RoundingMode);
     91
    4892} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r281788 r281838  
    164164#include "SymbolObject.h"
    165165#include "TemporalCalendar.h"
     166#include "TemporalDuration.h"
    166167#include "TestRunnerUtils.h"
    167168#include "ThunkGenerators.h"
     
    16201621DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlSegmenterSpace, intlSegmenterHeapCellType.get(), IntlSegmenter)
    16211622DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlSegmentsSpace, intlSegmentsHeapCellType.get(), IntlSegments)
     1623DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(temporalDurationSpace, cellHeapCellType.get(), TemporalDuration)
    16221624#if ENABLE(WEBASSEMBLY)
    16231625DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(jsToWasmICCalleeSpace, cellHeapCellType.get(), JSToWasmICCallee)
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r281788 r281838  
    186186#endif
    187187class Symbol;
     188class TemporalDuration;
    188189class TypedArrayController;
    189190class UnlinkedCodeBlock;
     
    618619    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlSegmenterSpace)
    619620    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlSegmentsSpace)
     621    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(temporalDurationSpace)
    620622#if ENABLE(WEBASSEMBLY)
    621623    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(jsToWasmICCalleeSpace)
Note: See TracChangeset for help on using the changeset viewer.