Browse Source

LibJS: Use narrower types in Temporal PlainDate/PlainDateTime/Calendar

These are bounds-checked during construction of PlainDate/PlainDateTime
and as such theres no need to widen them in these internal AO calls.
Idan Horowitz 4 years ago
parent
commit
2c6bd3a61b

+ 4 - 4
Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp

@@ -577,9 +577,9 @@ Optional<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject& global_
         VERIFY(sign_part.has_value());
 
         // b. Set hours to ! ToIntegerOrInfinity(hours).
-        i32 hours = Value(js_string(vm, *hours_part)).to_integer_or_infinity(global_object);
+        u8 hours = Value(js_string(vm, *hours_part)).to_integer_or_infinity(global_object);
 
-        i32 sign;
+        u8 sign;
         // c. If sign is the code unit 0x002D (HYPHEN-MINUS) or the code unit 0x2212 (MINUS SIGN), then
         if (sign_part->is_one_of("-", "\u2212")) {
             // i. Set sign to −1.
@@ -592,10 +592,10 @@ Optional<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject& global_
         }
 
         // e. Set minutes to ! ToIntegerOrInfinity(minutes).
-        i32 minutes = Value(js_string(vm, minutes_part.value_or(""sv))).to_integer_or_infinity(global_object);
+        u8 minutes = Value(js_string(vm, minutes_part.value_or(""sv))).to_integer_or_infinity(global_object);
 
         // f. Set seconds to ! ToIntegerOrInfinity(seconds).
-        i32 seconds = Value(js_string(vm, seconds_part.value_or(""sv))).to_integer_or_infinity(global_object);
+        u8 seconds = Value(js_string(vm, seconds_part.value_or(""sv))).to_integer_or_infinity(global_object);
 
         i32 nanoseconds;
         // g. If fraction is not undefined, then

+ 10 - 12
Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h

@@ -33,25 +33,23 @@ struct ISODateTime {
     Optional<String> calendar = {};
 };
 
-// FIXME: Use more narrow types for most of these (u8/u16)
 struct TemporalInstant {
     i32 year;
-    i32 month;
-    i32 day;
-    i32 hour;
-    i32 minute;
-    i32 second;
-    i32 millisecond;
-    i32 microsecond;
-    i32 nanosecond;
+    u8 month;
+    u8 day;
+    u8 hour;
+    u8 minute;
+    u8 second;
+    u16 millisecond;
+    u16 microsecond;
+    u16 nanosecond;
     Optional<String> time_zone_offset;
 };
 
-// FIXME: Use more narrow type for month/day (u8)
 struct TemporalDate {
     i32 year;
-    i32 month;
-    i32 day;
+    u8 month;
+    u8 day;
     Optional<String> calendar;
 };
 

+ 2 - 2
Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp

@@ -460,7 +460,7 @@ u16 iso_days_in_year(i32 year)
 }
 
 // 12.1.32 ISODaysInMonth ( year, month ), https://tc39.es/proposal-temporal/#sec-temporal-isodaysinmonth
-i32 iso_days_in_month(i32 year, i32 month)
+u8 iso_days_in_month(i32 year, u8 month)
 {
     // 1. Assert: year is an integer.
 
@@ -547,7 +547,7 @@ u8 to_iso_week_of_year(i32 year, u8 month, u8 day)
 }
 
 // 12.1.36 BuildISOMonthCode ( month ), https://tc39.es/proposal-temporal/#sec-buildisomonthcode
-String build_iso_month_code(i32 month)
+String build_iso_month_code(u8 month)
 {
     return String::formatted("M{:02}", month);
 }

+ 2 - 2
Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h

@@ -53,11 +53,11 @@ PlainDate* date_from_fields(GlobalObject&, Object& calendar, Object& fields, Obj
 bool calendar_equals(GlobalObject&, Object& one, Object& two);
 bool is_iso_leap_year(i32 year);
 u16 iso_days_in_year(i32 year);
-i32 iso_days_in_month(i32 year, i32 month);
+u8 iso_days_in_month(i32 year, u8 month);
 u8 to_iso_day_of_week(i32 year, u8 month, u8 day);
 u16 to_iso_day_of_year(i32 year, u8 month, u8 day);
 u8 to_iso_week_of_year(i32 year, u8 month, u8 day);
-String build_iso_month_code(i32 month);
+String build_iso_month_code(u8 month);
 double resolve_iso_month(GlobalObject&, Object& fields);
 Optional<TemporalDate> iso_date_from_fields(GlobalObject&, Object& fields, Object& options);
 i32 iso_year(Object& temporal_object);

+ 7 - 7
Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.cpp

@@ -14,7 +14,7 @@
 namespace JS::Temporal {
 
 // 3 Temporal.PlainDate Objects, https://tc39.es/proposal-temporal/#sec-temporal-plaindate-objects
-PlainDate::PlainDate(i32 year, i32 month, i32 day, Object& calendar, Object& prototype)
+PlainDate::PlainDate(i32 year, u8 month, u8 day, Object& calendar, Object& prototype)
     : Object(prototype)
     , m_iso_year(year)
     , m_iso_month(month)
@@ -29,7 +29,7 @@ void PlainDate::visit_edges(Visitor& visitor)
 }
 
 // 3.5.1 CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaldate
-PlainDate* create_temporal_date(GlobalObject& global_object, i32 iso_year, i32 iso_month, i32 iso_day, Object& calendar, FunctionObject* new_target)
+PlainDate* create_temporal_date(GlobalObject& global_object, i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, FunctionObject* new_target)
 {
     auto& vm = global_object.vm();
 
@@ -159,13 +159,13 @@ Optional<TemporalDate> regulate_iso_date(GlobalObject& global_object, double yea
         // IMPLEMENTATION DEFINED: This is an optimization that allows us to treat these doubles as normal integers from this point onwards.
         // This does not change the exposed behaviour as the call to IsValidISODate will immediately check that these values are valid ISO
         // values (for years: -273975 - 273975, for months: 1 - 12, for days: 1 - 31) all of which are subsets of this check.
-        if (!AK::is_within_range<i32>(year) || !AK::is_within_range<i32>(month) || !AK::is_within_range<i32>(day)) {
+        if (!AK::is_within_range<i32>(year) || !AK::is_within_range<u8>(month) || !AK::is_within_range<u8>(day)) {
             vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate);
             return {};
         }
         auto y = static_cast<i32>(year);
-        auto m = static_cast<i32>(month);
-        auto d = static_cast<i32>(day);
+        auto m = static_cast<u8>(month);
+        auto d = static_cast<u8>(day);
         // a. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception.
         if (is_valid_iso_date(y, m, d)) {
             vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate);
@@ -191,13 +191,13 @@ Optional<TemporalDate> regulate_iso_date(GlobalObject& global_object, double yea
         day = constrain_to_range(day, 1, iso_days_in_month(y, month));
 
         // c. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }.
-        return TemporalDate { .year = y, .month = static_cast<i32>(month), .day = static_cast<i32>(day), .calendar = {} };
+        return TemporalDate { .year = y, .month = static_cast<u8>(month), .day = static_cast<u8>(day), .calendar = {} };
     }
     VERIFY_NOT_REACHED();
 }
 
 // 3.5.5 IsValidISODate ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidisodate
-bool is_valid_iso_date(i32 year, i32 month, i32 day)
+bool is_valid_iso_date(i32 year, u8 month, u8 day)
 {
     // 1. Assert: year, month, and day are integers.
 

+ 9 - 9
Userland/Libraries/LibJS/Runtime/Temporal/PlainDate.h

@@ -15,12 +15,12 @@ class PlainDate final : public Object {
     JS_OBJECT(PlainDate, Object);
 
 public:
-    PlainDate(i32 iso_year, i32 iso_month, i32 iso_day, Object& calendar, Object& prototype);
+    PlainDate(i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, Object& prototype);
     virtual ~PlainDate() override = default;
 
     [[nodiscard]] i32 iso_year() const { return m_iso_year; }
-    [[nodiscard]] i32 iso_month() const { return m_iso_month; }
-    [[nodiscard]] i32 iso_day() const { return m_iso_day; }
+    [[nodiscard]] u8 iso_month() const { return m_iso_month; }
+    [[nodiscard]] u8 iso_day() const { return m_iso_day; }
     [[nodiscard]] Object const& calendar() const { return m_calendar; }
     [[nodiscard]] Object& calendar() { return m_calendar; }
 
@@ -28,15 +28,15 @@ private:
     virtual void visit_edges(Visitor&) override;
 
     // 3.4 Properties of Temporal.PlainDate Instances, https://tc39.es/proposal-temporal/#sec-properties-of-temporal-plaindate-instances
-    i32 m_iso_year { 0 };  // [[ISOYear]]
-    i32 m_iso_month { 1 }; // [[ISOMonth]]
-    i32 m_iso_day { 1 };   // [[ISODay]]
-    Object& m_calendar;    // [[Calendar]]
+    i32 m_iso_year { 0 }; // [[ISOYear]]
+    u8 m_iso_month { 1 }; // [[ISOMonth]]
+    u8 m_iso_day { 1 };   // [[ISODay]]
+    Object& m_calendar;   // [[Calendar]]
 };
 
-PlainDate* create_temporal_date(GlobalObject&, i32 iso_year, i32 iso_month, i32 iso_day, Object& calendar, FunctionObject* new_target = nullptr);
+PlainDate* create_temporal_date(GlobalObject&, i32 iso_year, u8 iso_month, u8 iso_day, Object& calendar, FunctionObject* new_target = nullptr);
 PlainDate* to_temporal_date(GlobalObject&, Value item, Object* options = nullptr);
 Optional<TemporalDate> regulate_iso_date(GlobalObject&, double year, double month, double day, String const& overflow);
-bool is_valid_iso_date(i32 year, i32 month, i32 day);
+bool is_valid_iso_date(i32 year, u8 month, u8 day);
 
 }

+ 1 - 1
Userland/Libraries/LibJS/Runtime/Temporal/PlainDateConstructor.cpp

@@ -84,7 +84,7 @@ Value PlainDateConstructor::construct(FunctionObject& new_target)
     // IMPLEMENTATION DEFINED: This is an optimization that allows us to treat these doubles as normal integers from this point onwards.
     // This does not change the exposed behaviour as the call to CreateTemporalDate will immediately check that these values are valid
     // ISO values (for years: -273975 - 273975, for months: 1 - 12, for days: 1 - 31) all of which are subsets of this check.
-    if (!AK::is_within_range<i32>(y) || !AK::is_within_range<i32>(m) || !AK::is_within_range<i32>(d)) {
+    if (!AK::is_within_range<i32>(y) || !AK::is_within_range<u8>(m) || !AK::is_within_range<u8>(d)) {
         vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDate);
         return {};
     }

+ 2 - 2
Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.cpp

@@ -36,7 +36,7 @@ void PlainDateTime::visit_edges(Visitor& visitor)
 }
 
 // 5.5.1 GetEpochFromISOParts ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-getepochfromisoparts
-BigInt* get_epoch_from_iso_parts(GlobalObject& global_object, i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond, i32 microsecond, i32 nanosecond)
+BigInt* get_epoch_from_iso_parts(GlobalObject& global_object, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond)
 {
     auto& vm = global_object.vm();
 
@@ -70,7 +70,7 @@ const auto DATETIME_NANOSECONDS_MIN = "-8640086400000000000000"_sbigint;
 const auto DATETIME_NANOSECONDS_MAX = "8640086400000000000000"_sbigint;
 
 // 5.5.2 ISODateTimeWithinLimits ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-isodatetimewithinlimits
-bool iso_date_time_within_limits(GlobalObject& global_object, i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond, i32 microsecond, i32 nanosecond)
+bool iso_date_time_within_limits(GlobalObject& global_object, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond)
 {
     // 1. Assert: year, month, day, hour, minute, second, millisecond, microsecond, and nanosecond are integers.
 

+ 2 - 2
Userland/Libraries/LibJS/Runtime/Temporal/PlainDateTime.h

@@ -46,8 +46,8 @@ private:
     Object& m_calendar;          // [[Calendar]]
 };
 
-BigInt* get_epoch_from_iso_parts(GlobalObject&, i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond, i32 microsecond, i32 nanosecond);
-bool iso_date_time_within_limits(GlobalObject&, i32 year, i32 month, i32 day, i32 hour, i32 minute, i32 second, i32 millisecond, i32 microsecond, i32 nanosecond);
+BigInt* get_epoch_from_iso_parts(GlobalObject&, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond);
+bool iso_date_time_within_limits(GlobalObject&, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond);
 PlainDateTime* create_temporal_date_time(GlobalObject&, i32 iso_year, u8 iso_month, u8 iso_day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Object& calendar, FunctionObject* new_target = nullptr);
 
 }

+ 7 - 7
Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp

@@ -10,42 +10,42 @@
 namespace JS::Temporal {
 
 // 4.5.5 IsValidTime ( hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidtime
-bool is_valid_time(i32 hour, i32 minute, i32 second, i32 millisecond, i32 microsecond, i32 nanosecond)
+bool is_valid_time(u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond)
 {
     // 1. Assert: hour, minute, second, millisecond, microsecond, and nanosecond are integers.
 
     // 2. If hour < 0 or hour > 23, then
-    if (hour < 0 || hour > 23) {
+    if (hour > 23) {
         // a. Return false.
         return false;
     }
 
     // 3. If minute < 0 or minute > 59, then
-    if (minute < 0 || minute > 59) {
+    if (minute > 59) {
         // a. Return false.
         return false;
     }
 
     // 4. If second < 0 or second > 59, then
-    if (second < 0 || second > 59) {
+    if (second > 59) {
         // a. Return false.
         return false;
     }
 
     // 5. If millisecond < 0 or millisecond > 999, then
-    if (millisecond < 0 || millisecond > 999) {
+    if (millisecond > 999) {
         // a. Return false.
         return false;
     }
 
     // 6. If microsecond < 0 or microsecond > 999, then
-    if (microsecond < 0 || microsecond > 999) {
+    if (microsecond > 999) {
         // a. Return false.
         return false;
     }
 
     // 7. If nanosecond < 0 or nanosecond > 999, then
-    if (nanosecond < 0 || nanosecond > 999) {
+    if (nanosecond > 999) {
         // a. Return false.
         return false;
     }

+ 1 - 1
Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.h

@@ -10,6 +10,6 @@
 
 namespace JS::Temporal {
 
-bool is_valid_time(i32 hour, i32 minute, i32 second, i32 millisecond, i32 microsecond, i32 nanosecond);
+bool is_valid_time(u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond);
 
 }